Why can't this Test::Unit test preserve the model across `post :create`?
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.
精彩评论