I just wasted some time by making a real dumb mistake in my unit testing setup, and I think that when tech bloggers do this they should publish the details, because wisdom is in large part the knowledge of how to avoid doing dumb things, and thus grows globally as a function of the published inventory of stupid mistakes. Thus, herewith, a description of how you can waste time by doing your unit testing just slightly wrong. [Updated: A suggested best practice to avoid this.] [And again.]
Scenario: you’re writing a class that has a real complex constructor, and
one that you’re pretty sure is going to be a performance bottleneck;
despite your best efforts to avoid premature optimization, you end up with an
80-line constructor including a couple of nested loops and a
binary search.
The rest of the methods have names like size()
and
first()
and don’t do much.
Using your best XP/TDD style, you bang out return null;
and
return -1;
bodies for all the little methods, and dive into
getting that constructor right, and then you really bear down on some good
unit tests for it.
Sure enough, the first few runs blow up in testConstructor()
with null pointers and infinite loops and so on, you fix them feeling
virtuous, this how TDD is supposed to go, right?
After a while, it’s not instantly blowing up, but you can’t seem to get your basic sanity-check tests to work, it seems that your constructor is laboring mightily and producing nothing. You end up single-stepping in the debugger, and sure enough, it sure looks like the object is getting constructed. But all the tests show it as empty.
At this point, you go elsewhere for coffee, except for walking down the
hall you say “Oh shit” out loud, because you suddenly remembered all those
return null;
and return -1;
stub methods that you
were going to get to later, and you’d used them in the Constructor test to
look at your object, hadn’t you?
How To Avoid This ·
In another hemisphere, Tony
Fisk shared a giggle at me around
his workplace, where a person named
Greg Presneill suggested: “Or, just throw a
System.NotImplementedException
instead
of arbitrary return -1;
or return null;
etc.”
That’s .NET-talk, the Java equivalent would be something like:
throw new RuntimeException("Method not implemented");
Obvious once you hear it, and immensely safer and better for stubs; I assume lots of people are already doing it.
A ton of people, way too many to list, suggested using
java.lang.UnsupportedOperationException
, which is a subclass of
RuntimeException
. Whatever, it doesn’t seem like that big a
deal.