Test code – not second-rank citizen

Some time ago I had the opportunity to browse some test code written as exercise. The code was actually written by a person quite into TDD, that’s why I got a bit surprised. The test code looked like it was written very long ago, and got abandoned shortly after its creation.

The exercise at some point required the solver to find negative numbers in a matrix (let’s just skip the other things not relevant for this post).¬† The first test method written against a method was called there_is_no_negative_number(). After that all the test cases followed the very same naming convention.

I, personally don’t like this naming style for several reasons:

  1. Test code should not differ from production code in format, coding conventions, naming conventions etc. I’ve never seen anyone naming methods in production – Java using underscores (and neither did the kata solver). That is the old C format. Java has its own coding standard, as Sun have clearly stated. Using the C style in tests and Java style in production doesn’t have any added value, but it’s rather harmful. It makes the code hard to read and it looks like two different people have written it. I am pretty sure no one would call a method parse_int() or value_of() in production code. Test code shouldn’t be any different.
  2. After reading the test method’s name one doesn’t get what the hell is going on in there. I mean we see there are no negative numbers, but where? In what context? Is it forbidden to have negatives or just a simple test case? What method is under test? What happens if there are no negative numbers? What if there are? This naming convention is rather rising questions than answering them. When I first met TDD, my mentor told me: simply by reading¬† a test’s name I should be able to tell what method is tested, for what parameters and what the return value will be. Then I learned about the “should-centric” test case naming convention. The test case above should be rather called -in this context- containsNegativeNumbersShouldReturnFalseIfTheInputContainsNoNegativeNumber. This name is kind of long, but much intuitive. As you can see all the questions above are answered by the test name itself. Imagine something going wrong in a huge code base. Which test would you rather see fail? In the first case you have to read all the test method body to figure out what the test is about. In the second case you just read the method name and get the context immediately. I’d definitely go with the long name.

Another thing I don’t really consider helpful is relaxing problem constraints in one direction only. In this concrete case the problem was relaxed horizontally. This means that the solver was trying to get the exercise done by first considering test cases for arrays only. Obviously arrays do not have all the properties matrices do, so these test cases are not taking us any further. However, relaxing constraints in both directions can be a good idea. In the case above (where we were given a matrix of four by four) it would have been nice to start with matrices of 1 by 1. 2 times 2 afterwards and so on.

In short, tests should be treated like production code, while problem dimensions should be relaxed symmetrically.