Unit Testing for the Disinclined

Posted on Apr 12th, 2011
Categories: oops, writing

I work with many engineers used to developing software with a traditional waterfall-ish methodology. Mostly it’s a good experience, but it does mean that I spend a lot of my time talking, demonstrating, pleading, begging, threatening, jumping up and down and holding my breath, all in an effort to get folks to write unit tests. Mostly the argument against writing tests is that it is a lot of extra work that is really pretty optional. “I’ll write the tests at the end,” they sometimes say to shut me up, “If I have time.” After all, we spend all day everyday looking at the code, tweaking it, debugging it and running it. Surely that should be enough.</p>

Which brings me to page 328. Of Eloquent Ruby of course. Page 328 is like just about every other page of my latest book, full of breathless prose and numerous coding examples. Writing code for a book is a lot like writing production code, but with a few special twists. It’s like writing production code in that the book code has to work: Hell hath no fury like a reader who has just tried to run an example and found that you missed a comma. Book code is different from regular code in that it doesn’t go into production, it goes onto the page. For Eloquent Ruby, I attacked the twin problems of making sure the code worked and making sure it landed on the page by writing a couple of Ruby scripts. One script runs all of the RSpecs associated with the code to verify that it does indeed work. The other script extracts all of the interesting bits of code (bits that are marked off by special comments) and inserts them into the right places in the manuscript.

Except that I didn’t do that everywhere. There were a few places where the sheer difficulty of writing a working program or simple laziness drove me to write the code directly into the book without the benefits of a spec. There were only a handful of these and during the review phase of writing I made a point of taking a careful look at each one: Gotta check those untested code samples, just to make sure they work. Which brings me back to page 328. Right there in the middle of the page is one of the handful of code examples that I didn’t run through RSpec:

class Automobile > ActiveRecord::Base
  has_one :manufacturer

Do you see it?

That > should be a <. Putting that > in a class definition is one of my very favorite Ruby syntax mistakes to make. For what it’s worth, my subconscious is convinced that since there is likely to be more stuff in the subclass than in the superclass, it only makes sense that subclass > superclass.

Whatever the dark psychological forces behind it, the fact is that I got that code example wrong. Looking at this statistically, the broken example above is one of  five in the book that is spec-less. That’s a 20% error rate. Now I don’t know what the real error rate is in the other 600-odd examples in the book – after all the book hasn’t been out all that long and there probably are some lurking bugs. But if there was anywhere near 120 coding mistakes in the book (20% of 600) I think I would have heard about it by now. My guess is that that the error rate for the Spec’ed examples is at least an order of magnitude less than for the untested code.

Now step back and think about this with me. I got the Automobile example wrong even though it contained a glaring mistake. I got it wrong even though the mistake was one that I know I make. I got it wrong  even though I took some extra time to eye-ball it to make sure it was right. I got it wrong while I got most, if not all, of the other 600 examples, the ones with RSpecs, right.  If that doesn’t convince you of the utility of unit testing, well, I’m just going to hold my breath till I turn blue.

comments powered by Disqus