Wednesday, January 6, 2010

Test the edge cases

In yesterday's post, I argued that for an easy method like calculating age, the first block of C# had a real "code smell" to it that made it obvious that there were a couple of bugs and that it looked overly complicated.  I went and dug out code from my codebase at work - code I didn't write, but it's code that gets hit all the time.  But did you notice that that block of VB code has an insidious bug that the first block of C# code doesn't have? I didn't at first either.  Have a look again and see if you can spot it.


Here's a test that will highlight the problem:

Dim dob = #6/2/1979#
Dim dt = #6/1/2009# ' day before 30th b-day
Assert.AreEqual(Util.Age(dob, dt), 29) ' WORKS!

dob = #6/2/1978# ' Lets use 1978 now...
Dim dt = #6/1/2008# ' day before 30th b-day
Assert.AreEqual(Util.Age(dob, dt), 29) ' FAILS!  WHAT!?

What happened here?  The second method, the one I argued yesterday was terse and still readable and therefore better has a bug in it on leap years.  Let me state Matt's axioms of programming 101 -
  1. All significant code has bugs.
  2. If you think your code is bug free, see axiom #1
  3. Code that looks bad has obvious bugs
  4. Code that looks elegant still has bugs, but you're less likely to see them
 The only defense against bugs - and it isn't foolproof - is testing.  If your code doesn't have tests, you don't know where the bugs are.  If your code only has simple tests, then you've only protected against the simple bugs.  One of the most important skills to have as a developer is the ability to see the edge cases, and test against them.  We don't have good tests written at my work, and it's one of my New Years resolutions to fix that problem.