Miniformats for Tests

So you’re building out a fairly complex component — one of those things that, try as you might, you really can’t simplify any further. Consider what happens when you start building out your tests for this component. You get all your really basic unit tests done quickly — things like
• “make sure this function returns a positive integer
• “validate that the user count is never zero
and so on.

The fun begins when you start layering on functionality. For example your widget’s state includes a whole bunch of opaque internal structures with a variety of bit-patterns, hashes, and whatnot — and your widget does…stuff…based on these structures.
Your tests very rapidly end up containing depressingly long sections of code, all designed to say stuff like

// set up my widget
var widget = new Object();
widget.hash_start_section = "deadbeef";
widget.constructor_type = 1337;
.
.
// continues forever...

And that’s on a good day. On a bad day, you do horrible stuff like serialize the utterly opaque widget state into a string (text = serializeWidgetToString(my_widget)) and then unserialize it in each test.
Which is, of course, utterly horrible because you then need to re-serialize the widget every time you change something, and that happens a lot, and now you need a beer…

A pretty nifty way to avoid this — albeit one that takes a bit more effort — is to create a human readable text file that you use for these widgets. YAML or JSON preferably, but depending on the complexity of your state, you might want to roll your own (don’t, unless you have to! And even then, don’t!). Then, set up your tests so that they can read/write this format. Nelson Elhage calls this a“miniformat”, so hey, let’s go with that.

The advantages are fairly obvious. The human readability ensures that you actually know what the widget looks like, and the rigor involved in reading/writing the miniformat will ensure that you actually think through the impact of changes to the widget. And, of course, you can add/update the tests by manipulating the miniformats. And yes, of course can level up by automating the generation of these files too…

One final note here — if, at some point, you realize that there is way too much effort going into maintaining the miniformat and/or the readers/writers, then it’s a pretty good sign that you need to do some serious refactoring on the widget 😀.

(This article also appears on my blog)