“找不到 #<User ...> 的有效映射";仅在第二次和连续测试中 [英] &quot;Could not find a valid mapping for #&lt;User ...&gt;&quot; only on second and successive tests

查看:12
本文介绍了“找不到 #<User ...> 的有效映射";仅在第二次和连续测试中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个请求测试,该测试断言正确的链接出现在应用程序布局上,具体取决于用户是登录还是注销.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 =>:controller 但这仅适用于控制器测试,不适用于请求测试.

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

现在,考虑以下集成测试

Now, consider the following integration test

# 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 问题(我倾向于怀疑它,因为我可以在其他地方使用用户工厂而没有问题)还是设计问题(我在设置 gem 后开始收到这些错误我的应用程序,但我也只有一个其他请求测试,它确实工作正常,但现在出现了 AssociationTypeMismatch 错误;相关性≠因果关系...)或 RSpec 问题或其他一些奇怪的边缘情况 gem 冲突.

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.

推荐答案

感谢:http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-rails-3-console/

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆