Почему этот Test :: Unit test не может сохранить модель в `post: create`?

#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 это не сработало бы.