Paul: OK. I hadn't thought of that but I can see how it might become a problem. I'll give it some thought. What about the
assert_raised assertions in the
test_destroy method? I know we just used
assert_nothing_raised to trap a fatal exception in our Category Unit test. But why would the Rails scaffolding use it here? The
find doesn't throw a fatal exception.
CB: Good question, Paul. And you're right, in Rails, an unsuccessful
find throws an exception, but it's not a fatal one. You probably remember that in our Unit tests we invoked
Category.find several times without checking for an Exception. We used
assert_not_nil to test that a record was successfully retrieved, and
assert_nil to test that a record was not successfully retrieved. Here, Rails' test scaffolding is doing the same tests a different way: by checking to see if a RecordNotFound Exception was raised. Even though a
find doesn't really drive the need, I think there are a couple of good reasons to show this approach in the
First, we know that Rails throws a fatal exception when we try to destroy an object that has children. So, for starters, if Rails is going to scaffold this approach in any of the test methods, this is a pretty good one. Second, we added the
check_for_children method to our Category model to fix the problem in the app. If that weren't the case, and if the Category record had any child records in the Recipes table, this test would crash our test case. If we thought there was a risk that the
check_for_children method might get lost, instead of POSTing a request to destroy the record, we could invoke
Category.destroy inside one of these two assertions. Then the Exception will be trapped and the test method will just pass or fail, depending on the situation, instead of crashing our test case. I'm not suggesting we do that here, because we already have a Unit test,
test_cannot_delete_record_with_child, that covers us. In fact, we used
assert_nothing_raised in that test. I'm just reminding you that these assertions give us the ability to do it here too.
Paul: I'm ready to give it a shot. Here goes...
I think I want to go ahead and add a test method for the
verify. I like the idea of having a specific test that could help decrease our debug time if something happened to it. So I'll add...
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
test_list method, I need to add a new assertion to make sure we test for the creation of both instance variables the controller method is creating.
test_show method is OK, and we've already covered the test methods for the
create methods in the controller. The
test_edit method is OK too. Which brings us to the
The scaffolded method is only testing a successful
update, just like the
test_create method was doing before we fixed it. So I think we ought to make the same sort of change here.
CB: That's fine. But before you do, I want to make sure we're on the same page as to why we're doing what we're doing. In the
test_create_success_and_failure method you followed the path that the Rails scaffolding had laid down for us; checking the number of records to verify a successful
create and failed
create. There's nothing wrong with that. But do we really need to do that test in our Functional tests?
Paul: I'm not following you. Why wouldn't we want to make sure the app actually did what it says it did?
CB: Our Unit tests are already testing to validate that the CRUD functionality is working.
Paul: Ahhh... I see what you're saying. So, the question is "do you really want to repeat yourself?" I think you're right. We don't need to do that test again here.
CB: I didn't say we don't. I asked. Let me ask it differently. Is there some value we might get if we did decide to repeat the test here in our Functional test? Say, for example, that we ran our Unit tests and they passed. And then we ran our Functional tests and this one failed. Would that tell us something of value?
Paul: Yeah. It would tell us that something bad had happened to our Unit tests.
CB: Exactly. So, if we think the probability of that happening is high, we might want to go ahead and duplicate the test, but more with the intent of testing our tests, and not so much to retest our app.
Paul: I see what you're saying. Thanks for making me think about it. In fact, I was thinking about doing pretty much the same thing we did in our Unit test; changing the data and then retrieving it to make sure it actually got changed in the database. But now that I think about it, maybe there's a better way to approach this. What do you think about this?
def test_update post :update, :id => @first_id assert_response :redirect assert_redirected_to :action => 'show', :id => @first_id post :update, :id => @first_id, :name => '' assert_template 'edit' end
CB: That looks like a pretty good first stab at it. Let's run the test case and see what we get.
Paul: Good idea.
So, what do you think? You good to go?