Cookin' with Ruby on Rails - Integration Tests
Pages: 1, 2, 3, 4, 5, 6, 7

And now we'll rerun our test case...

test results after adding the beef to our content test
Figure 15

CB: What do you think, Boss? You want to walk us through the changes I made to the test?

Boss: Well... I think I understand some of it. I know enough HTML to see that we're testing the table a row at a time. And for each row we're looking for three divisions, and we're looking at the content within each division. One thing I don't understand though is the content you're looking for. Like the dates. Those aren't the same dates I'm seeing in the browser I'm looking at with Paul.

Paul: I can explain that, Boss. It's something we didn't talk about with you yet. The content we're looking for in the tests is coming from what're called test fixtures. Let me open up the recipes fixture and show you.

recipes fixture
Figure 16

The tests use a copy of the database that's just for testing. It's got exactly the same structure as the database the app's using to display what you're seeing in the browser, but the test database is getting its content from the test fixtures. The test database gets emptied and reloaded before each test method is executed. If it weren't for that, we'd have to put a lot more effort into planning and controlling the order of execution of the test methods in order to fully test the application, and we'd need to create a lot more test data. With Rails, we can delete a record in one test method, and then use that same record in another.

Boss: Thanks, Paul. That answers my question. And it's probably about as much as I need to know: same results for less work. I like it. But speaking of deleting records, we need to make sure the app can do that, don't we? And add them?

CB: You bet, Boss. I'll go ahead and add a new test method for the delete.

def verify_a_recipe_can_be_deleted
  recipe_count_before_delete = Recipe.find(:all).size
  post "recipe/destroy/1"
  recipe_count_after_delete = Recipe.find(:all).size
  assert_equal(recipe_count_after_delete, recipe_count_before_delete - 1)  

Boss: Hmmm....

CB: What's wrong, Boss?

Boss: If I understand that code, you're checking the number of records in the database. Right? And that's important. But what I need to know is not what's in the database. I need to know that what's on the page in the browser is right.

CB: You're absolutely right, Boss. My bad. And now that I think about it, that focus gives me an idea that'll make our test code better. I'm going to chop up the method that checks our table content so we can reuse parts of it here. So, now we've got...

test method refactored into component parts
Figure 17

Now, I'll rerun the tests to make sure I haven't messed up anything with the change...

same results
Figure 18

And now I'll change our test method for the recipe deletion so that it checks the page, not the database, to verify that there's no link to the deleted recipe.

def verify_a_recipe_can_be_deleted
  post "recipe/destroy/1"
  assert_response :redirect
  assert_template "recipe/list"
  assert_select "tr", :count => 2
  assert_raise(Test::Unit::AssertionFailedError) {assert_select "a", {:text=>"pizza"}}

NOTE to Readers: Make sure that the {assert_select ...} block appears in your code on the same line as the assert_raise() method it belongs to. Rails will throw a syntax error if it doesn't.

CB: And now I'll add the method call to the top level test method so that the new tests get executed.

our updated top-level test method
Figure 19

Pages: 1, 2, 3, 4, 5, 6, 7

Next Pagearrow