使用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
就是这样,测试失败…登录失败.在将“调试器”调用插入规范和控制器之后,我可以看到为什么:就控制器而言,用户没有被插入到数据库中:
编辑在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
在控制台中,在上述断点处:
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 >
但是,如果我在我的测试中重新排列了几行,那么把“二”放在“一”之上:
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 => '2468' click_button 'Sign in' page.should have_content('Logged in') end end
我在控制台中得到这个(与上述相同的断点):
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
为了简洁起见,我省略了用户对象内容的全部转储,但是我可以向您保证测试按预期完成.
这种交换线路来测试通过的行为与我对这些命令应该发生什么的想法并不十分吻合,并且证明对我在其他领域的测试是相当痛苦的.
关于这里发生了什么的提示?
为了解决这个问题,我已经对google和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,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 []
解决方法
在工厂女孩邮件列表的帮助下,我发现了这个问题.
默认情况下,RSpec使用事务来保持数据库处于干净状态,每个事务都绑定到线程.沿着管道的某个地方,visit_page命令分解,绑定到当前线程的事务会消失.
解决方案很简单:禁用事务.
describe "Sessions" do self.use_transactional_fixtures = false it 'no longer uses transactions' do #whatever you want end end
更新Rails 5.1
从Rails 5.1起,use_transactional_fixtures已被弃用,应替换为use_transactional_tests.
self.use_transactional_tests = false