Ruby on rails 测试RoR教程中的失败(第9.4章)

Ruby on rails 测试RoR教程中的失败(第9.4章),ruby-on-rails,ruby,ruby-on-rails-3,rspec,railstutorial.org,Ruby On Rails,Ruby,Ruby On Rails 3,Rspec,Railstutorial.org,我正在学习RoR教程第9.4章。当所有的rspec测试都变成绿色时,我的测试就不能正常工作了。我运行bundle exec rspec spec/并得到四个失败,错误如下: Failures: 1) User pages index signup page with valid information after saving the user Failure/Error: sign_in user NoMethodError: undefined met

我正在学习RoR教程第9.4章。当所有的rspec测试都变成绿色时,我的测试就不能正常工作了。我运行bundle exec rspec spec/并得到四个失败,错误如下:

Failures:

  1) User pages index signup page with valid information after saving the user
     Failure/Error: sign_in user
     NoMethodError:
       undefined method `email' for nil:NilClass
     # ./spec/support/utilities.rb:23:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:12:in `block (3 levels) in <top (requi
red)>'

  2) User pages index signup page with valid information after saving the user
     Failure/Error: sign_in user
     NoMethodError:
       undefined method `email' for nil:NilClass
     # ./spec/support/utilities.rb:23:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:12:in `block (3 levels) in <top (requi
red)>'

  3) User pages index signup page with valid information after saving the user
     Failure/Error: sign_in user
     NoMethodError:
       undefined method `email' for nil:NilClass
     # ./spec/support/utilities.rb:23:in `sign_in'
     # ./spec/requests/user_pages_spec.rb:12:in `block (3 levels) in <top (requi
red)>'

  4) Authentication signin with invalid information after visiting another page

     Failure/Error: it { should_not have_selector('div.alert.alert-error') }
       expected #has_selector?("div.alert.alert-error") to return false, got tru
e
     # ./spec/requests/authentication_pages_spec.rb:26:in `block (5 levels) in <
top (required)>'

Finished in 21.33 seconds
81 examples, 4 failures
用户\u页面\u spec.rb:

require 'spec_helper'

describe "User pages" do

  subject { page }

  describe "index" do

    let(:user) { FactoryGirl.create(:user) }

    before do
      sign_in user
      visit users_path
    end

    it { should have_title('All users') }
    it { should have_content('All users') }

    describe "pagination" do

      before(:all) { 30.times { FactoryGirl.create(:user) } }
      after(:all)  { User.delete_all }

      it { should have_selector('div.pagination') }

      it "should list each user" do
        User.paginate(page: 1).each do |user|
          expect(page).to have_selector('li', text: user.name)
        end
      end
    end

   describe "delete links" do

      it { should_not have_link('delete') }

      describe "delete links" do

      it { should_not have_link('delete') }

      describe "as an admin user" do
        let(:admin) { FactoryGirl.create(:admin) }
        before do
          sign_in admin
          visit users_path
        end

        it { should have_link('delete', href: user_path(User.first)) }
        it "should be able to delete another user" do
          expect do
            click_link('delete', match: :first)
          end.to change(User, :count).by(-1)
        end
        it { should_not have_link('delete', href: user_path(admin)) }
      end
    end
  end


  describe "profile page" do
    let(:user) { FactoryGirl.create(:user) }
    before { visit user_path(user) }

    it { should have_content(user.name) }
    it { should have_title(user.name) }
  end

    describe "signup page" do

    before { visit signup_path }

    let(:submit) { "Create my account" }

    describe "with invalid information" do
      it "should not create a user" do
        expect { click_button submit }.not_to change(User, :count)
      end
    end

    describe "with valid information" do
      before do
        fill_in "Name",         with: "Example User"
        fill_in "Email",        with: "user@example.com"
        fill_in "Password",     with: "foobar"
        fill_in "Confirmation", with: "foobar"
      end

      it "should create a user" do
        expect { click_button submit }.to change(User, :count).by(1)
      end

      describe "after saving the user" do
        before { click_button submit }
        let(:user) { User.find_by(email: 'user@example.com') }

        it { should have_link('Sign out') }
        it { should have_title(user.name) }
        it { should have_selector('div.alert.alert-success', text: 'Welcome') }
      end

    end
  end

    describe "edit" do
    let(:user) { FactoryGirl.create(:user) }
    before do
      sign_in user
      visit edit_user_path(user)
    end

    describe "page" do
      it { should have_content("Update your profile") }
      it { should have_title("Edit user") }
      it { should have_link('change', href: 'http://gravatar.com/emails') }
    end

    describe "with valid information" do
      let(:new_name)  { "New Name" }
      let(:new_email) { "new@example.com" }
      before do
        fill_in "Name",             with: new_name
        fill_in "Email",            with: new_email
        fill_in "Password",         with: user.password
        fill_in "Confirm Password", with: user.password
        click_button "Save changes"
      end

      it { should have_title(new_name) }
      it { should have_selector('div.alert.alert-success') }
      it { should have_link('Sign out', href: signout_path) }
      specify { expect(user.reload.name).to  eq new_name }
      specify { expect(user.reload.email).to eq new_email }
    end
    end
end
end
身份验证\u页面\u spec.rb:

require 'spec_helper'

describe "Authentication" do

  subject { page }

  describe "signin page" do
    before { visit signin_path }

    it { should have_content('Sign in') }
    it { should have_title('Sign in') }
  end

describe "signin" do

    before { visit signin_path }

    describe "with invalid information" do
      before { click_button "Sign in" }

      it { should have_title('Sign in') }
      it { should have_selector('div.alert.alert-error') }

      describe "after visiting another page" do
        before { click_link "Home" }
        it { should_not have_selector('div.alert.alert-error') }
      end
    end


  describe "with valid information" do
      let(:user) { FactoryGirl.create(:user) }
      before { sign_in user }

      it { should have_title(user.name) }
      it { should have_link('Users',       href: users_path) }
      it { should have_link('Profile',     href: user_path(user)) }
      it { should have_link('Settings',    href: edit_user_path(user)) }
      it { should have_link('Sign out',    href: signout_path) }
      it { should_not have_link('Sign in', href: signin_path) }



    describe "follower by signout" do
      before {click_link "Sign out"}
      it {should have_link('Sign in')}
      end
    end
  end

 describe "authorization" do

    describe "for non-signed-in users" do
      let(:user) { FactoryGirl.create(:user) }

      describe "when attempting to visit a protected page" do
        before do
          visit edit_user_path(user)
          fill_in "Email", with: user.email
          fill_in "Password", with: user.password
          click_button "Sign in"
        end

        describe "after signing in" do

          it "should render the desired protected page" do
            expect(page).to have_title('Edit user')
          end
        end
      end

      describe "in the Users controller" do

        describe "visiting the edit page" do
          before { visit edit_user_path(user) }
          it { should have_title('Sign in') }
        end


        describe "submitting to the update action" do
          before { patch user_path(user) }
          specify { expect(response).to redirect_to(signin_path) }
        end
      end
        describe "visiting the user index" do
          before { visit users_path }
          it { should have_title('Sign in') }
        end

    end

    describe "as wrong user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:wrong_user) { FactoryGirl.create(:user, email: "wrong@example.com") }
      before { sign_in user, no_capybara: true }

      describe "submitting a GET request to the Users#edit action" do
        before { get edit_user_path(wrong_user) }
        specify { expect(response.body).not_to match(full_title('Edit user')) }
        specify { expect(response).to redirect_to(root_url) }
      end

      describe "submitting a PATCH request to the Users#update action" do
        before { patch user_path(wrong_user) }
        specify { expect(response).to redirect_to(root_url) }
      end
    end

   describe "as non-admin user" do
      let(:user) { FactoryGirl.create(:user) }
      let(:non_admin) { FactoryGirl.create(:user) }

      before { sign_in non_admin, no_capybara: true }

      describe "submitting a DELETE request to the Users#destroy action" do
        before { delete user_path(user) }
        specify { expect(response).to redirect_to(root_url) }
      end
    end
  end
end
user.rb

class User < ActiveRecord::Base
  has_secure_password
  before_save { self.email = email.downcase }
  before_create :create_remember_token
  validates :name, presence: true, length: { maximum: 50 }
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i
  validates :email, presence: true, format: { with: VALID_EMAIL_REGEX },
                    uniqueness: { case_sensitive: false }
  has_secure_password
  validates :password, length: { minimum: 6 }

  def User.new_remember_token
    SecureRandom.urlsafe_base64
  end

  def User.encrypt(token)
    Digest::SHA1.hexdigest(token.to_s)
  end

  private

    def create_remember_token
      self.remember_token = User.encrypt(User.new_remember_token)
    end

end
rails控制台测试:

irb(main):001:0> **user = FactoryGirl.build(:user)**
=> #<User id: nil, name: "Person 1", email: "person_1@example.com", created_at:
nil, updated_at: nil, password_digest: "$2a$04$LiRdaarU6QaX9PJa1uFjE.5e44SYRsmy1
OMY8A4EKZow...", remember_token: nil, admin: false>

irb(main):002:0> **user.valid?**
  User Exists (1.0ms)  SELECT 1 AS one FROM "users" WHERE LOWER("users"."email")
 = LOWER('person_1@example.com') LIMIT 1
=> true

irb(main):003:0> **user.errors**
=> #<ActiveModel::Errors:0x49dd678 @base=#<User id: nil, name: "Person 1", email
: "person_1@example.com", created_at: nil, updated_at: nil, password_digest: "$2
a$04$LiRdaarU6QaX9PJa1uFjE.5e44SYRsmy1OMY8A4EKZow...", remember_token: nil, admi
n: false>, @messages={}>
我更改了users_controller.rb,现在只有3个1-3个故障

用户\u controller.rb:

          class UsersController < ApplicationController
  before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: :destroy

  def index
    @users = User.paginate(page: params[:page])
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

   def create
    @user = User.new(user_params)
    if @user.save
      sign_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end

   def edit
   end

  def update
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user 
      # Handle a successful update.
    else
      render 'edit'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted."
    redirect_to users_url
  end

  private

  def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end

    # Before filters

    def signed_in_user
      unless signed_in?
        store_location
        redirect_to signin_url, notice: "Please sign in."
      end
    end


    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end


  def admin_user
      redirect_to(root_url) unless current_user.admin?
    end

end
实际项目版本-。也许这有助于找到失败的原因/

user\u page\u spec.rb中的一条结束语句放错了位置。描述索引块应在描述配置文件页面之前结束

i、 e

注册用于注册新用户,因此测试不应首先让用户登录


顺便说一句,您还描述了两次删除链接,嵌套在其内部,尽管这不会是错误的原因;它只是重复一个测试。

如果我们也能在spec/factories.rb中看到工厂:用户是如何定义的,那就太好了,因为您已经以不同的方式定义了有效的电子邮件正则表达式

对于初学者,您可以将regex条件还原回原始状态:

  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i

确保验证部分与您的factory:user一起工作


并删除第二个密码以确保安全。

您需要共享实际代码并测试失败的代码,而不仅仅是测试结果。让我们看看app/models/user.rb您是否也可以添加您的用户工厂。根据我下面的回答,您是否可以转到rails控制台测试,然后做user=FactoryGirl.build:user然后检查user.valid?还有user.errors.抱歉伙计-我再尝试一次。。。注册页面的测试正在描述索引块中运行。您的意思是在描述删除链接之前结束描述索引块吗?鉴于您正在测试注册功能,您可能不想在此之前登录。希望这是有意义的…我删除了第二个密码并更改了有效的电子邮件注册表。但仍然有相同的4次失败。
          class UsersController < ApplicationController
  before_action :signed_in_user, only: [:index, :edit, :update, :destroy]
  before_action :correct_user,   only: [:edit, :update]
  before_action :admin_user,     only: :destroy

  def index
    @users = User.paginate(page: params[:page])
  end

  def show
    @user = User.find(params[:id])
  end

  def new
    @user = User.new
  end

   def create
    @user = User.new(user_params)
    if @user.save
      sign_in @user
      flash[:success] = "Welcome to the Sample App!"
      redirect_to @user
    else
      render 'new'
    end
  end

   def edit
   end

  def update
    if @user.update_attributes(user_params)
      flash[:success] = "Profile updated"
      redirect_to @user 
      # Handle a successful update.
    else
      render 'edit'
    end
  end

  def destroy
    User.find(params[:id]).destroy
    flash[:success] = "User deleted."
    redirect_to users_url
  end

  private

  def user_params
      params.require(:user).permit(:name, :email, :password,
                                   :password_confirmation)
    end

    # Before filters

    def signed_in_user
      unless signed_in?
        store_location
        redirect_to signin_url, notice: "Please sign in."
      end
    end


    def correct_user
      @user = User.find(params[:id])
      redirect_to(root_url) unless current_user?(@user)
    end


  def admin_user
      redirect_to(root_url) unless current_user.admin?
    end

end
describe "index" do
  ...
  describe "pagination" do
    ...
  end

  describe "delete links" do
    ...
  end
end

describe "profile page" do
  ...
end

describe "signup page" do
  ...
end 

etc.
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i