"Не удалось найти допустимое сопоставление для # <User...>" только во втором и последующих тестах
Я пытаюсь написать тест запроса, который утверждает, что правильные ссылки отображаются на макете приложения в зависимости от того, вошел ли пользователь в систему или нет. FWIW, я использую Devise для части аутентификации.
Здесь моя спецификация:
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
Первый тест проходит, но последние три с ошибкой
Failure/Error: @user = Factory(:user, :password => "Asd123", :password_confirmation => "Asd123")
RuntimeError:
Could not find a valid mapping for #<User id: xxx, ...>
Я искал в вики Google, группе Google и результатах поиска причину, но все, что я нахожу, - это неотвеченные вопросы или предложения по установке config.include Devise::TestHelpers, :type => :controller
, но это относится только к испытаниям контроллера, а не к тесту запроса.
Обновление
Я сделал еще несколько проблем, и я не могу сделать головы или хвосты того, что в конечном итоге вызывает проблему. Посмотрите на следующий код.
Во-первых, для некоторого контекста здесь есть объявление пользователя factory. Он отлично работает в модульных тестах.
# 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 => "[email protected]",
# :email_confirmation => "[email protected]",
# :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 '/'
на что-нибудь еще (или вообще ничего), тесты все будут работать нормально.
Итак, я не знаю, является ли это проблемой factory_girl (я склонен сомневаться в этом, так как я могу использовать фабрики Пользователей в другом месте без проблемы) или проблему разработки (я начал получать эти ошибки после настройки этого драгоценного камня в мое приложение, но у меня также был только один другой тестовый запрос, который отлично работал, но теперь он получает ошибку AssociationTypeMismatch, корреляцию ≠ причинность...) или проблему RSpec или какой-то другой странный конфликтный случай с камнем.
Ответы
Ответ 1
Благодаря: http://blog.thefrontiergroup.com.au/2011/03/reloading-factory-girl-factories-in-the-rails-3-console/
"Devise использует сопоставление между классами и маршрутами, поэтому, когда объект factory приходит через Devise после перезагрузки консоли или переопределения класса, тогда он будет терпеть неудачу."
Поместите это в инициализатор или 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
Ответ 2
Добавьте эту строку в ваши маршруты.
# Devise routes
devise_for :users # Or the name of your custom model
Ответ 3
Для будущих читателей: я получил ту же ошибку, но по другой причине.
В нашем приложении было несколько пользовательских моделей, в которых один был получен из другого
Для аргументов:
class SimpleUser
class User < SimpleUser
В моем контроллере я использовал ссылку на SimpleUser (родительский класс), но Devise был настроен на использование User (дочерний класс).
Во время вызова Devise:: Mapping.find_scope! он делает .is_a? сравнение с ссылкой на объект и сконфигурированный класс.
Поскольку моя ссылка была SimpleUser, а сконфигурированный класс был User,.is_a? терпит неудачу, потому что сравнение спрашивает, является ли класс родителя is_a? Класс Child, который всегда является ложным.
Надеюсь, что это поможет кому-то другому.
Ответ 4
У меня была эта ошибка в файле маршрутов, потому что у меня была конечная точка API, из которой я хотел разрешить пользователям использовать reset свои пароли, но я хотел, чтобы пользователи действительно делали изменение пароля в веб-представлении, t namespaced под /api
Вот как я исправил маршруты, чтобы заставить его работать:
CoolApp::Application.routes.draw do
namespace :api, defaults: { format: :json } do
devise_scope :users do
post 'users/passwords', to: 'passwords#create'
end
resources :users, only: [:create, :update]
end
devise_for :users
root to: 'high_voltage/pages#show', id: 'home'
end
Ответ 5
Я знаю, что это старый поток, но мне нужен был ответ на того, кто еще это использует. не знаю, где я это прочитал, но реквизит для человека, который опубликовал об этом на другом форуме.
Длинный, а короткий - это то, что тестовые помощники разработки не работают с интеграционными тестами.
Поэтому удалите все ссылки для Devise:: TestHelpers (некоторые из них используют include, другие люди используют "devise/testhelpers" ) из самих спецификаций.
то в файле spec_helper добавьте:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
Ответ 6
Решение Halfnelson тоже работало для меня, но поскольку я использую "Изготовление драгоценного камня" вместо FactoryGirl, мне нужно было внести некоторые коррективы. Здесь код, который я запустил в инициализатор:
if Rails.env.development? || Rails.env.test?
ActionDispatch::Callbacks.after do
Fabrication.clear_definitions
Rails.logger.debug 'Reloading fabricators'
end
end
Ответ 7
На всякий случай, если кто-то еще сталкивается с этим, по той же причине, что и я, у меня была такая же проблема в основном во всех моих тестах после изменения некоторых файлов конфигурации. Оказалось, что из-за того, что RAILS_ENV
установлено значение development
, когда я случайно провел тесты. Возможно, стоит проверить перед добавлением тестового релейного инициализатора:-)
Ответ 8
В моем случае это было проблемой с методом Devis confirm!
. Поэтому вместо этого (Minitest::Test
code):
setup do
@admin = create(:admin).confirm!
end
Я сделал это:
setup do
@admin = create(:admin)
@admin.confirm!
end
И это сработало:)
Ответ 9
Это случалось со мной раньше, когда я вошел в систему в качестве тестового пользователя в одном из моих приложений и сделал несколько тестовых загрузок и тестовых сообщений. Затем я удалил этого тестового пользователя, и когда я попытался снова зарегистрироваться с тем же тестовым пользователем, мне было показано сообщение "Не удалось найти действительное сопоставление для nil". Чтобы решить эту проблему, я удалил все тестовые загрузки и тестовое сообщение, которое я сделал как этот тестовый пользователь. Затем я попытался зарегистрироваться снова, и это сработало. Таким образом, более быстрый и простой способ удалить материал - использовать db browser для sqlite.