Friday, June 20, 2008

Test the Entire Method

I'm working on a project that - among other things - takes in a set of data points and spits out a bar chart on the UI. These charts describe things like number of messages per day over the past two weeks. The project is a Ruby on Rails app, and to generate the graphs, we use Gruff. Gruff internally uses RMagick to actually draw the images. Basically, you feed Gruff your data points and it gives you back a PNG.*

So, how to test this thing?

With Gruff as it stands, you can feed it test data and check that the PNG comes back. So my test looks like this:

def test_messages_chart
  get :messages_chart, {}, {:session_id => "1"}
  assert_equal "images/png", @response.content_type
  assert_equal 500, assigns['bar_chart'].width
  assert_equal 250, assigns['bar_chart'].height

This is great as far as it goes.  But I'm not the trusting type, and nowhere am I actually asserting that the right values got onto that chart. And there's a lot going on in the messages_chart method. It has to:
  1. figure out how many days of data to show
  2. query the db to get that data
  3. hand the data off to Gruff (which then munges the data and calls RMagick to actually draw the picture)
  4. get the image from Gruff and display it
My test code can tell me that items 3 and 4 worked right - I get a picture, after all. It doesn't tell me that we did items 1 and 2 right. Looks like my test is incomplete. And it was incomplete because Gruff didn't let me assert on the values that had been fed into it. I wound up having to write a mixin for Gruff to allow me to get the values for each data point, and then added that to my test.

But the moral of the story is that if at all possible, you should look at your method and make sure you're testing all of it. Don't let your tools dictate what you test; make your test dictate what your tools should do.

* As a side note, this is a great way to do these types of graphs. It really eliminates the overhead of maintaining CSS-based graphs across browsers.

No comments:

Post a Comment