使用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 >
但是,如果我在测试中重新排列几行,那么就行了两行&#39;以上行&#39;一个&#39;:
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
我在控制台中得到了这个(与上面相同的断点):
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
为了简洁起见,我省略了用户对象内容的完整转储,但我可以向您保证测试按预期完成。
交换行以使测试通过的这种行为并不能很好地适应我对这些命令应该发生什么的想法,并且已经证明对我在其他领域的测试非常重要。
这里有什么提示?
我已经搜索了谷歌和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
[]
那么访问的方式显然告诉Factory Girl它是用用户对象完成的,所以她删除了它?
编辑仔细检查test.log后,没有任何内容发出任何删除。所以我或多或少地回到原点。
答案 0 :(得分: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
Rails 5.1更新
自Rails 5.1起,use_transactional_fixtures
已弃用,应替换为use_transactional_tests
。
self.use_transactional_tests = false
答案 1 :(得分:3)
我认为RSpec中的用户变量已经覆盖了控制器中的用户变量,所以它不起作用? (在测试中无法获得正确的user.email)
之前:
user = Factory(:user)
user.password! '2468'
visit '/sessions/index' # user gets overwritten
fill_in 'Email', :with => user.email # can't get user.email
之后:
visit '/sessions/index' # Execute action
user = Factory(:user) # user gets overwritten
user.password! '2468'
fill_in 'Email', :with => user.email # user.email works
答案 2 :(得分:1)
这在技术上不是一个答案,更多的是评论,但澄清代码是最简单的机制。
您可以尝试执行以下操作来帮助缩小用户被销毁的位置
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'
# check the user's definitely there before page load
puts User.first
#line two
visit '/sessions/index'
# check the user's still there after page load
puts User.first.reload
fill_in 'Email', :with => user.email
fill_in 'Password', :with => '2468'
click_button 'Sign in'
# check the user's still there on submission (though evidently not)
puts User.first.reload
page.should have_content('Logged in')
end
end
修改强>
它在现实生活中适用于你而不是在Capybara中的事实表明它可能是现有会话信息的产物。当您在浏览器中进行测试时,您通常会在之前的工作中退出,但Capybara总是从干净的会话开始。
您可以通过清除所有Cookie(我相信您已知道)或只需切换到Chrome / FF中的新隐身窗口即可轻松查看浏览器中的Capybara错误,这是一种很好的快捷方式得到一个干净的会议。
答案 3 :(得分:0)
上面的正确答案对我有所帮助。当然,我需要更改一些其他测试(错误地或正确地)假设夹具不存在。有关更多信息:在Capybara README中有关于此的一些信息。
https://github.com/jnicklas/capybara
“如果您正在使用SQL数据库,则通常在事务中运行每个测试,该测试在测试结束时回滚,例如,rspec-rails默认情况下开箱即用。”通常不会跨线程共享,这会导致您在测试代码中放入数据库的数据对Capybara不可见。“
您也可以在手动测试后配置RSpec进行清理:
https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Cleanup-after-your-Rspec-tests