使用Rspec进行测试会出错,但使用浏览器进行测试工作正常

时间:2014-09-20 18:08:46

标签: ruby-on-rails-4 rspec

朋友您好我先要承认一下,我以前的帐号被禁止提问,从现在开始,我会尽量让问题更清晰准确!

我正在研究Hartl的ruby on rails教程,我一直坚持chapter 9.2.2 Requiring the right user`#34;清单9.13测试编辑和更新操作需要合适的用户&#34 ;几天。我已经做了很多研究,我在章节中来回走动,它没有工作,似乎没有人有我现在的问题。让我详细解释一下。

错误:

Authentication authorization as wrong user submitting a GET request to the Users#edit action 
     Failure/Error: specify { expect(response.body).not_to match(full_title('Edit user')) }
     TypeError:
       wrong argument type nil (expected Regexp)
     # ./spec/requests/authentication_pages_spec.rb:61:in `block (5 levels) in <top (required)>'

Finished in 1.77 seconds
64 examples, 1 failure

我已经与浏览器进行了测试,它运行良好,我试图编辑其他用户。该页面已成功定向到主页!

Github:https://github.com/Snailseason2014/Sample

这里有一些相关的文件:

规格/请求/ authentication_pages_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', text: 'Invalid') }

      describe 'after visiting another page' do
        before { click_link 'Home' }
        it { should_not have_selector('div.alert.alter-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('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 'followed 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 '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
    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
  end
end

应用程序/控制器/ users_controller.rb

class UsersController < ApplicationController
  before_action :signed_in_user, only: [:edit, :update]
  before_action :correct_user,   only: [:edit, :update]
  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'
      redirect_to @user
    else
      render 'new'
    end
  end

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

  def update
    # @user = User.find(params[:id])
    if @user.update_attributes(user_params)
      flash[:success] = 'Profile updated'
      redirect_to @user
    else
      render 'edit'
    end
  end

  private

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

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

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

2 个答案:

答案 0 :(得分:1)

在您的规范中:

expect(response.body).not_to match(full_title('Edit user'))

预期match exepctation会将某些文本与正则表达式匹配,例如:

expect("hello").to match(/ell/)   # => true
expect("hello").to match(/blah/)  # => false

full_title('Edit user')不是正则表达式...它是页面上的一些内容。所以在expect...match中使用它确实不合适。您可以将任何字符串转换为正则表达式,方法是将其置于//并使用字符串插值语法,例如:

a_string = 'some string'
a_regex = /#{a_string}/

所以在这里你可以使用:

expect(response.body).not_to match(/#{full_title('Edit user')}/)

但是......你得到的错误信息表明更深层次......它表示你传递的是nil而不是正则表达式...这意味着full_title('Edit user')正在评估为nil而不是一个实际的字符串。

如果您使用上面的示例...规范可能仍然会失败...所以您必须弄清楚为什么full-title('Edit user')返回nil并首先修复它。

答案 1 :(得分:1)

看起来你跳过了一些练习,特别是第5.6节中的练习,这可以防止你的错误。

在任何情况下,在第5章中,教程都要为要使用的测试定义一个重复的full_title()帮助程序,该帮助程序将放在文件中:

spec/support/utilities.rb

视图使用了原始的full_title()助手。

查看您的spec/support/utilities.rb文件,您有:

def full_title(page_title)
  base_title = 'Ruby on Rails Tutorial Sample App'
  if page_title.empty?
    base_title
  else
    "#{base_title} | #{page_title}"
  end

你能看出什么是错的吗?很明显,您从教程的文本中复制并粘贴了该代码,并且错过了最后一行:end,这是关闭您在第一行开始的def所必需的。但是,我无法解释为什么在尝试运行测试时没有得到SyntaxError,这会在我尝试时阻止测试运行。