“找不到#< User ...>”的有效映射仅在第二次和连续测试 [英] "Could not find a valid mapping for #<User ...>" only on second and successive tests
问题描述
我正在尝试编写一个请求测试,断言应用程序布局上显示正确的链接,具体取决于用户是登录还是退出。 FWIW,我正在使用Devise进行身份验证。
I'm trying to write a request test that asserts that the proper links appear on the application layout depending in whether a user is logged in or out. FWIW, I'm using Devise for the authentication piece.
这是我的规格:
require 'spec_helper'
require 'devise/test_helpers'
describe "Layout Links" do
context "the home page" do
context "session controls" do
context "for an authenticated user" do
before do
# I know these should all operate in isolation, but I
# want to make sure the user is explicitly logged out
visit destroy_user_session_path
@user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
@user.confirm!
# I tried adding this per the Devise wiki, but no change
@request.env["devise.mapping"] = Devise.mappings[:user]
# Now log a new user in
visit new_user_session_path
fill_in "Email", :with => @user.email
fill_in "Password", :with => "Asd123"
click_button "Sign in"
get '/'
end
it "should not have a link to the sign in page" do
response.should_not have_selector(
'#session a',
:href => new_user_session_path
)
end
it "should not have a link to registration page" do
response.should_not have_selector(
'#session a',
:href => new_user_registration_path
)
end
it "should have a link to the edit profile page" do
response.should have_selector(
'#session a',
:content => "My Profile",
:href => edit_user_registration_path
)
end
it "should have a link to sign out page" do
response.should have_selector(
'#session a',
:content => "Logout",
:href => destroy_user_session_path
)
end
end # context "for an authenticated user"
end # context "session controls"
end
end
第一个测试通过,但最后三个都失败,错误
The first test passes, but the last three all fail with the error
Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
RuntimeError:
Could not find a valid mapping for #<User id: xxx, ...>
我通过Devise wiki,Google群组和搜索结果搜索了一个原因,但是我所有的找到没有答案的问题或建议设置 config.include Devise :: TestHelpers,:type => :控制器
,但仅适用于控制器测试,不适用于测试。
I've searched through the Devise wiki, Google group and search results for a cause, but all I find are unanswered questions or suggestions to set config.include Devise::TestHelpers, :type => :controller
but that only applies to controller tests, not request test.
更新
我已经做了一些更多的故障排除,我无法做出最终触发问题的头部或尾部。看看下面的代码。
I've done some more troubleshooting and I can't make heads or tails of what is ultimately triggering the problem. Have a look at the following code.
首先,对于某些上下文是用户工厂声明。它在单元测试中工作正常。
First, for some context here is the User factory declaration. It works fine in unit tests.
# spec/factories.rb
Factory.define :user do |f|
f.email { Faker::Internet.email }
f.email_confirmation { |f| f.email }
f.password "AbcD3fG"
f.password_confirmation "AbcD3fG"
f.remember_me { (Random.new.rand(0..1) == 1) ? true : false }
end
现在考虑以下集成测试
# spec/requests/user_links_spec.rb
require "spec_helper"
describe "User Links" do
before(:each) do
# This doesn't trigger the problem
# @user = nil
# This doesn't trigger the problem
# @user = User.new
# This doesn't trigger the problem
# @user = User.create(
# :email => "foo@bar.co",
# :email_confirmation => "foo@bar.co",
# :password => "asdf1234",
# :password_confirmation => "asdf1234"
# )
# This doesn't trigger the problem
# @user = User.new
# @user.email = Faker::Internet.email
# @user.email_confirmation = @user.email
# @user.password = "AbcD3fG"
# @user.password_confirmation = "AbcD3fG"
# @user.remember_me = (Random.new.rand(0..1) == 1) ? true : false
# @user.save!
# This triggers the problem!
@user = Factory(:user)
# This doesn't trigger the same problem, but it raises a ActiveRecord::AssociationTypeMismatch error instead. Still no idea why. It was working fine before in other request tests.
# @user = Factory(:brand)
end
context "when using `@user = Factory(:user)` in the setup: " do
2.times do |i|
it "this should pass on the 1st iteration, but not the 2nd (iteration ##{i+1})" do
# This doesn't trigger an error
true.should_not eql(false)
end
it "this should pass on the 1st iteration, but trigger the error that causes all successive test cases to fail (iteration ##{i+1})" do
# Every test case after this will be borken!
get '/'
end
it "this will fail on all iterations (iteration ##{i+1})" do
# This will now trigger an error
true.should_not eql(false)
end
end
end
end
如果我们评论或替换其他任何东西(或根本没有)的 get'/'
位置,测试全部运行正常。
If we comment out or replace the get '/'
bit with anything else (or nothing at all), the tests all run fine.
所以,我不知道这是否是一个factory_girl问题(我倾向于怀疑,因为我可以在其他地方使用用户工厂)一个Devise问题(在我的应用程序中设置该gem之后,我开始收到这些错误,但是我也只有另外一个请求测试可以正常工作,但是现在得到了AssociationTypeMismatch错误;关联≠因果关系...)或RSpec问题或一些其他奇怪的边缘宝石冲突。
So, I don't know if this is a factory_girl issue (I tend to doubt it since I can use User factories elsewhere w/o issue) or a Devise issue (I started getting these errors after setting up that gem in my application, but I also only had one other request test which did work fine but is now getting that AssociationTypeMismatch error; correlation ≠ causation...) or an RSpec issue or some other weird edge-case gem conflict.
推荐答案
Devise使用类和路由之间的映射,所以当工厂建立的对象通过Devise后控制台重新加载或类重新定义,那么它将失败。
"Devise uses a mapping between classes and routes, so when a factory built object comes through to Devise after a console reload, or a class redefinition then it will fail."
将其放在初始化程序或application.rb
Put this in an initializer or application.rb
ActionDispatch::Callbacks.after do
# Reload the factories
return unless (Rails.env.development? || Rails.env.test?)
unless FactoryGirl.factories.blank? # first init will load factories, this should only run on subsequent reloads
FactoryGirl.factories.clear
FactoryGirl.find_definitions
end
end
这篇关于“找不到#< User ...>”的有效映射仅在第二次和连续测试的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!