Tabular unit tests

Last week during kata exercises I realised that I prefer my unit test assertions to form “tables”. For example, here is one of the JUnit tests we developed for a simple object that extracts the quote-delimited strings from a text:


public void testNoStringsDetected() {
  assertNoStringsFound("");
  assertNoStringsFound("blah blah");
  assertNoStringsFound("blah \"blah");
  assertNoStringsFound("\"blah");
  assertNoStringsFound("blah \"");
  assertNoStringsFound("\"");
}

private static void assertNoStringsFound(String text) {
  assertEquals(0, new StringExtractor(text).strings().size());
}

The testNoStringsDetected() method is formatted as a “table” of testcases, one per line. And to make that work, we defined a little helper method in the form of a bespoke assertion, assertNoStringsFound(). Note that we didn’t set out with the aim of developing tabular tests. We were doing TDD, adding test methods one by one and making them pass. Then at some point we noticed some duplication, so we extracted the helper assertion. Then we collapsed the test methods into the single table above.

The main benefit of this approach is that the table is easy to scan for completeness. In fact, after we had arrived at this form by refactoring, we quickly spotted a couple of additional boundary cases that we hadn’t seen when each assertion was in its own method.

During the dojo, development of these tests was interleaved with more complex cases, such as those in which the input contains a single string. We were refactoring those as we went too, and the result was this:


public void testOneStringDetected() {
  assertOneStringFound("abc \"def\" ghi", "def");
  assertOneStringFound("\"def\" ghi",     "def");
  assertOneStringFound("abc \"def\"",     "def");
  assertOneStringFound("\"def\"",         "def");
}

private static void assertOneStringFound(String text, String expected) {
  List actual = new StringExtractor(text).strings();
  assertEquals(1, actual.size());
  assertEquals(expected, actual.get(0));
}

This time the “table” has two columns: the first defines the inputs and the second the expected outputs. Again we defined a helper assertion – and again it was this that led directly to discovery of the tabular form for these tests.

I’ve been testing this way for years, but only since the advent of TDD and refactoring has the process made itself clear to me:

  1. write test cases individually, beginning with very simple boundary cases;
  2. strive to keep the test code clean, simple and free from duplication, just as with the production code;
  3. where there’s a repeated expression, extract a helper method;
  4. where the repetition includes an assertion, call the helper method assertXXX();
  5. collect the resulting 1-line tests together into tables;
  6. complete the tables where additional boundary cases now become obvious.

This isn’t a panacaea, but it works in surprisingly many circumstances. And it always produces tests that are more readable, more complete and more adaptable. I commend it to the house.

Update, 27-feb-06
Synchronicity! Gerard Meszaros pointed me at TDD Pattern: Tabular Tests, a recent blog post by Clint Shank on the very same topic.

Advertisements

2 thoughts on “Tabular unit tests

  1. Pingback: It’s bikesheds all the way down | silk and spinach

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s