#ruby-on-rails #factory-bot #testunit
#ruby-on-rails #factory-бот #testunit
Вопрос:
У меня есть две модели: User
и Topic
. У пользователей может быть много тем, и темы принадлежат одному пользователю.
В моем контроллере тем я пытаюсь протестировать действие create для допустимой темы:
Тест
# topics_controller.test.rb
def test_create_valid
sign_in Factory(:user) # Devise will redirect you to the login page otherwise.
topic = Factory.build :topic
post :create, :topic => topic
assert_redirected_to topic_path(assigns(:topic))
end
Фабрика (Factory Girl)
# factories.rb
Factory.define :user do |f|
f.sequence(:username) { |n| "foo#{n}"}
f.password "password"
f.password_confirmation { |u| u.password}
f.sequence(:email) { |n| "foo#{n}@example.com"}
end
Factory.define :topic do |f|
f.name "test topic"
f.association :creator, :factory => :user
end
Результат теста
ERROR test_create_valid (0.59s)
ActionController::RoutingError: No route matches {:action=>"show", :controller=>"topics", :id=>#<Topic id: nil, name: nil, created_at: nil, updated_at: nil, creator_id: 1>}
/usr/local/lib/ruby/gems/1.9.1/gems/actionpack-3.0.7/lib/action_dispatch/routing/route_set.rb:425:in `raise_routing_error'
В тесте topic.valid?
имеет значение true и topic.name
имеет заводское значение.
Однако post, похоже, не проходит мимо post :create, :topic => topic
. Похоже, что она никогда не сохраняется в базе данных, поскольку у нее даже нет идентификатора в выходных данных теста.
Редактировать: Даже если я обойду фабрику для новой темы, это не сработает.
def test_create_valid
@user = Factory :user
sign_in @user
topic = @user.topics.build(:name => "Valid name.")
post :create, :topic => topic
assert_redirected_to topic_path(assigns(:topic))
end
Приводит к той же тестовой ошибке.
Ответ №1:
post
Метод здесь ожидает параметры в качестве второго аргумента, а не объекты. Это потому, что create
действие в вашем контроллере будет использовать params
метод для извлечения этих параметров и использования их в процессе создания нового раздела, используя код, подобный этому:
Topic.new(params[:topic])
Таким образом, ваши params[:topic]
должны быть атрибутами проекта, который вы хотите создать, а не существующего Topic
объекта. Однако вы могли бы использовать Factory.build :topic
для получения экземпляра Topic
объекта, а затем сделать это, чтобы заставить его работать:
post :create, :topic => topic.attributes
Ответ №2:
Это настолько далеко за пределами моего понимания, но, по-видимому, мне пришлось вручную установить атрибут в post :create
параметрах. Кажется довольно нелогичным, учитывая, что :topic => topic
это такая идиома Rails.
def test_create_valid
sign_in @user
topic = Factory.build :topic
post :create, :topic => {:name => topic.name}
assert_redirected_to topic_path(assigns(:topic))
end
Надеюсь, кто-нибудь сможет пролить некоторый свет на то, почему post :create, :topic => topic
это не сработало бы.