Factory Girl/Capybara从数据库测试中删除记录?

vox*_*uro 14 ruby-on-rails capybara rspec2 rspec-rails factory-bot

与RSpec和Capybara合作,我得到了一个有趣的测试失败模式,它在测试用例中有一些细微的线条重排......这些都不重要.

我正在开发自己的身份验证系统.它目前正在工作,我可以使用浏览器和会话工作等登录/退出.但是,尝试测试这是失败的.正在发生的事情我不太明白,这似乎取决于(看似)不相关的电话的顺序.

require 'spec_helper'

describe "Sessions" do
  it 'allows user to login' do
    #line one
    user = Factory(:user)
    #For SO, this method hashes the input password and saves the record
    user.password! '2468'

    #line two
    visit '/sessions/index'


    fill_in 'Email', :with => user.email
    fill_in 'Password', :with => '2468'
    click_button 'Sign in'

    page.should have_content('Logged in')
  end
end
Run Code Online (Sandbox Code Playgroud)

原样,该测试失败......登录失败.在将'调试器'调用插入规范和控制器后,我可以看到原因:就控制器而言,用户没有插入数据库:

编辑在ApplicationController中添加

class ApplicationController < ActionController::Base
  helper :all
  protect_from_forgery

  helper_method :user_signed_in?, :guest_user?, :current_user

  def user_signed_in?
    !(session[:user_id].nil? || current_user.new_record?)
  end

  def guest_user?
    current_user.new_record?
  end

  def current_user
    @current_user ||= session[:user_id].nil? ? User.new : User.find(session[:user_id])
  rescue ActiveRecord::RecordNotFound
    @current_user = User.new
    flash[:notice] = 'You\'ve been logged out.'
  end
end


class SessionsController < ApplicationController
  def login
    user = User.where(:email=>params[:user][:email]).first

    debugger ###

    if !user.nil? && user.valid_password?(params[:user][:password])
      #engage session
    else
      #run away
    end
  end

  def logout
    reset_session
    redirect_to root_path, :notice => 'Logget Out.'
  end
end
Run Code Online (Sandbox Code Playgroud)

在控制台中,在上面的断点处:

1.9.2 vox@Alpha:~/Sites/website$ rspec spec/controllers/sessions_controller_spec.rb 
/Users/vox/Sites/website/app/controllers/sessions_controller.rb:7
if !user.nil? && user.valid_password?(params[:user][:password])
(rdb:1) irb
ruby-1.9.2-p180 :001 > User.all.count
 => 0 
ruby-1.9.2-p180 :002 > 
Run Code Online (Sandbox Code Playgroud)

但是,如果我在测试中重新排列几行,将第二行放在'one'行上方:

describe "Sessions" do
  it 'allows user to login' do
    #line two
    visit '/sessions/index'

    #line one
    user = Factory(:user)
    #For SO, this method hashes the input password and saves the record
    user.password! '2468'


    fill_in 'Email', :with => user.email
    fill_in 'Password', :with => '2468'
    click_button 'Sign in'

    page.should have_content('Logged in')
  end
end
Run Code Online (Sandbox Code Playgroud)

我在控制台中得到这个(与上面相同的断点):

1.9.2 vox@Alpha:~/Sites/website$ rspec spec/controllers/sessions_controller_spec.rb 
/Users/vox/Sites/website/app/controllers/sessions_controller.rb:7
if !user.nil? && user.valid_password?(params[:user][:password])
(rdb:1) irb
ruby-1.9.2-p180 :001 > User.all.count
 => 1 
Run Code Online (Sandbox Code Playgroud)

为了简洁起见,我省略了用户对象内容的完整转储,但我可以向您保证测试按预期完成.

交换行以使测试通过的这种行为并不能很好地适应我对这些命令应该发生什么的想法,并且已经证明对我在其他领域的测试非常重要.

关于这里发生了什么的任何暗示?

我已经搜索了谷歌和SO的想法,提出了这个问题,并且不乏关于RSpec/Capybara和Sessions的SO问题.似乎没有什么比较合适了.

谢谢你的期待.

更新

我已经添加了一个断点(就在访问调用之前)并对测试进行了一些调试并返回:

(rdb:1) user
#<User id: 1, login_count: 1, email: "testuser1@website.com", encrypted_password: "11f40764d011926eccd5a102c532a2b469d8e71249f3c6e2f8b...", salt: "1313613794">
(rdb:1) User.all
[#<User id: 1, login_count: 1, email: "testuser1@website.com", encrypted_password: "11f40764d011926eccd5a102c532a2b469d8e71249f3c6e2f8b...", salt: "1313613794">]
(rdb:1) next
/Users/vox/Sites/website/spec/controllers/sessions_controller_spec.rb:19
fill_in 'Email', :with => user.email
(rdb:1) User.all
[]
Run Code Online (Sandbox Code Playgroud)

很明显,访问的方式是告诉Factory Girl它是否完成了用户对象,所以她删除了它?

编辑仔细检查test.log后,没有任何内容发出任何删除.所以我或多或少地回到原点.

vox*_*uro 23

在Factory Girl邮件列表的帮助下,我发现了这个问题.

默认情况下,RSpec使用事务来将数据库维护在干净状态,并且每个事务都与一个线程相关联.沿着管道的某处,visit_page命令分离,并且绑定到当前线程的事务终止.

解决方案很简单:禁用事务.

describe "Sessions" do
  self.use_transactional_fixtures = false

   it 'no longer uses transactions' do
     #whatever you want
  end
end
Run Code Online (Sandbox Code Playgroud)

Rails 5.1的更新

从Rails 5.1开始,use_transactional_fixtures已弃用,应替换为use_transactional_tests.

self.use_transactional_tests = false
Run Code Online (Sandbox Code Playgroud)

  • 最好在spec_helper.rb中进行设置. (3认同)