Cookin' with Ruby on Rails - More Designing for Testability
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
Looking good! Looks like we're ready to move on to the category controller test. Let's go ahead and fix the reference to the :first fixture before we do. In the setup method, change...
@first_id = recipies(:first)
to
@first_id = recipes(:one)
And since we know that recipes need to have a title and to be assigned to a category for our validations to work, let's go ahead and change the line in the test_create method to avoid that error. Change...
post :create, :recipe => {}
to
post :create, :recipe => {:title => "new recipe", :category_id => 1}
And now let's give our recipe controller test a run to see where we are on that.
ruby test\functional\recipe_controller_test.rb

Figure 32
Paul: I'd say that's a pretty good start ;-)
CB: Gotta agree with you there, Paul ;-) You want to take us through the changes we need to make?
Paul: Sure. I'll just start at the top again. The test_index method looks OK. I'm going to copy over the test_verify_gets_are_safe method from the category controller test.
def test_verify_gets_are_safe get :destroy assert_redirected_to :action => 'list' get :create assert_redirected_to :action => 'list' get :update assert_redirected_to :action => 'list' end
We changed the list method in the recipe controller so it would filter for a category, though, so it's different from the list method in the category controller.

Figure 33
I think we need to beef up our test method here. Here's what we've got now.

Figure 34
Paul: This test doesn't pass in anything for the category_id param so that takes care of the first branch in the list method. I think we just need to do a second pass in here passing in the category_id and making sure the same assertions still pass. It doesn't make sense to me to try to make sure that only the right records were returned, especially not in the controller test. If we were going to test for that, I'd say we'd need to do it in the Unit tests. What do you think?
CB: Sounds good to me.
Paul: Cool. So, I'm going to replace the test_list method with one I'll name test_list_all_and_filtered.
def test_list_all_and_filtered get :list assert_response :success assert_template 'list' assert_not_nil assigns(:recipes) get :list, :category_id => '1' assert_response :success assert_template 'list' assert_not_nil assigns(:recipes) end
The test_show and test_new methods are OK, but the test_create needs the same treatment we gave it in the category controller test. So I'll replace test_create with test_create_success_and_failure. pretty much just like we did before, except for the variable names. We just have to remember that recipes need both a title and the foreign key to save successfully.
def test_create_success_and_failure
num_recipes = Recipe.count
post :create, :recipe => {:title => "new recipe", :category_id => 1}
assert_response :redirect
assert_redirected_to :action => 'list'
assert_not_nil flash[:notice]
assert_equal num_recipes + 1, Recipe.count
num_recipes = Recipe.count
post :create, :recipe => {:title => ""}
assert_response :success
assert_template 'new'
assert_equal num_recipes, Recipe.count
end
For the test_update method, we need to make sure invalid updates generate errors, just like we did in the category controller. So we'll add the same two lines to the end of the method.
post :update, :id => @first_id, :title => '' assert :redirect
Which brings us to the test_destroy method which, on the same reasoning we came to in the category controller, seems to be OK for the moment.







