开发者

Why can't this Test::Unit test preserve the model across `post :create`?

开发者 https://www.devze.com 2023-03-04 14:54 出处:网络
I have 开发者_JAVA百科two models: User and Topic. Users can have many topics and topics belong to one user.

I have 开发者_JAVA百科two models: User and Topic. Users can have many topics and topics belong to one user.

In my Topics controller, I'm trying to test the create action for a valid topic:

The Test

  # 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

The Factory (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

The Test Output

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'

In the test, topic.valid? is true and topic.name has a value from the factory.

However, the post doesn't seem to make it past post :create, :topic => topic. It looks like it's never saved in the database since it doesn't even have an id in the test output.

Edit: Even if I bypass the Factory for the new topic, it doesn't work.

  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

Results in the same test error.


The post method here expects parameters as the second argument, not objects. This is because the create action in your controller is going to be using the params method to retrieve these parameters and use them in the process of creating a new topic, using code like this:

Topic.new(params[:topic])

So therefore your params[:topic] needs to be the attributes of the project you want to create, not an existing Topic object. However, you could use Factory.build :topic to get an instantiated Topic object and then do this to make it work:

post :create, :topic => topic.attributes


This is so far beyond me, but I apparently had to manually set the attribute in the post :create params. Seems pretty counter-intuitive given that :topic => topic is such a Rails idiom.

  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

Hopefully someone can shed some light on why post :create, :topic => topic wouldn't work.

0

精彩评论

暂无评论...
验证码 换一张
取 消