Who cares how long the test is?!

I was speaking with someone at BarCamp and they suggested that your unit test should never be longer than the thing it’s testing. His thinking was that if your test is longer than what it’s testing then your tests will eventually need a test framework to make sure they’re correct. This was of course one of his excuses for not writing tests at all. And, superficially at least, there is some validity to his argument, but it’s based on a flawed premise. It’s based on the premise that the code you write in your test suite is complex enough that it too could be brittle, and if you ever find this happening it’s a sure sign that you’re doing in wrong.

Let me explain: Unit Tests should be simple… really simple. Each test routine should basically have these parts:

  • An instance of the thing you’re testing.
  • If it requires parameters in it’s constructor or in the method you’re testing you create some mock objects (not stubs) to pass it.
  • A series of assertions to test that what you thought would happen did happen.

Instantiating an object is not a complex operation. It’s usually something along the lines of

Bar myBar = new Bar();

You don’t have to worry about that breaking, normally because constructors don’t tend to do much. If your constructor does have any complexity happening under the covers then you’ve got a unit test for it somewhere else and thus you don’t have to worry about it.

Creating a mock object not only avoids potential complexity but utilizes a well tested library so you don’t need to test that either. Yeah it may take a few lines but it isn’t complex or brittle and it is guaranteed to work exactly as you tell it to.

Assertions are just

assertEquals("camels", myBar.favoriteAnimal()); // or maybe...

First off, the assertions themselves are methods from a unit testing suite, you can rest assured that they not only work correctly but have full unit test coverage. So you don’t have to worry about them. Second, they’re brain dead simple. There’s no logic, so there’s nothing to break. The only thing here with the potential to blow up is the methods you’re testing and that’s why you wrote the test in the first place.

Your unit test should have absolutely no business logic in it. If it does then you probably need to refactor your code.

So, lets look at a simple concrete example of why the length of your method is irrelevant to the length of your test.

Most of you are familiar with QuickSort. It’s a simple and fast method to sort a list of things. You can probably write a QuickSort algorithm in under 15 lines of code. So what happens if you pass your quicksort algorithm a list of twenty shuffled items. You’d want to test that it correctly sorted all twenty of them wouldn’t you? Considering that this is a test you know exactly what the input is and exactly what the output should be, but there’s only one way to really test it. You have to check every slot of the returned list and make sure it’s got the correct item in it. So that’s at least one line to set up the list you’re going to pass to your quicksort method, one line to pass it in, and twenty lines to test the results. Something like this:

SortingUtilities sortUtils = new SortUtils(); 
String[] unsortedMen = new String[]{"tom", "dick", "Harry"......and 17 more}; 
String[] sortedMen = sortUtils.myQuickSortMethod(unsortedMen);
assertEquals("dick", sortedMen[0]); 
assertEquals("Harry", sortedMen[1]); 
// case insensitivity testing too assertEquals("tom", sortedMen[2]); 
// and so on for another 16 lines

Grand total of 23 lines plus 2 more to start and end the test method itself, plus you’d probably want to break that list of unsortedMen down into multiple lines so it would be readable. All that just to test a fifteen line method. For good measure you might want to add a line to test that the size of the array that came out is the same as the size of the array that went in, just to make sure that nothing was accidentally duplicated in there. But nothing, nothing, in that list even remotely needs to be tested itself because it’s all brain dead simple. There’s nothing complex. There’s no business logic, there’s nothing you have to worry about. The fact that it happens to have more lines than the method it’s testing is totally irrelevant.

The only excuse I’ll hear for not wanting to do this is that you’re too damn lazy. At least that’s honest. But claiming that the length of your test suite has any relevance to the length of the method under test is just plain ignorant.

You’re a programmer. Use your brain. Don’t make poorly thought out, half-assed excuses not to do the right thing. If you’re going to avoid doing the right thing at least be honest about why you’re doing it. Laziness sucks, but at least it’s honest, and since people don’t generally like thinking of themselves as lazy it has the potential to kick your ass into gear. And, because it always comes up, the excuse that writing all those lines of test code “slows you down” or “takes too long” is bullshit because we all know that the vast majority of time spent on any project is in debugging and maintenance and when you’ve got good tests that time is dramatically reduced. You end up saving far more time than you spent writing your tests, and your end result is just more bug free and stable. If typing out twenty lines of brain dead assertions takes you more than a minute and a half you need to get off your butt and take a typing course.