Naming Test Methods
Thursday 13 May 2010 14:37
Picking names sensibly in code is crucial to readability. For instance, let's say you're storing prices in your database, and they're represented by a Price
class. What does a PriceHelper
do? Naming something a helper isn't helpful in the least. On the other hand, the class PriceFetcher
probably fetches prices from somewhere. Others have written about what names not to use for classes, but I want to talk about a different set of names. I want to talk about how we name our tests. For instance, let's say I'm implementing a join
method in Java that will glue together a list of strings. Being a good programmer, I write a test to describe its behaviour:
class JoinTest { @Test public void testJoin() { assertEquals("", join(", ", emptyList())); assertEquals("Apples", join(", ", asList("Apples"))); assertEquals( "Apples, Bananas, Coconuts", join(", ", asList("Apples", "Bananas", "Coconuts")) ); } }
So, what's wrong with calling the method testJoin
? The answer is that the method tells us nothing about what we expect to happen, just that we're testing the join
method. By picking a name that describes what we expect, we can help the next reader of the code to understand what's going on a little better:
class JoinTest { @Test public void joiningEmptyListReturnsEmptyString() { assertEquals("", join(", ", emptyList())); } @Test public void joiningListOfOneStringReturnsThatString() { assertEquals("Apples", join(", ", asList("Apples"))); } @Test public void joiningListOfStringsConcatenatesThoseStringsSeparatedBySeparator() { assertEquals( "Apples, Bananas, Coconuts", join(", ", asList("Apples", "Bananas", "Coconuts")) ); } }
Splitting up tests in this fashion also means that it's easier to pin down failures since you can easily work out exactly what test cases are failing.
This works well with Test Driven Development (TDD). Each time you want to add a new behaviour and extend the specification a little further by adding a failing test, the test method describes the new behaviour in both the test code and its name. In fact, having rearranged the code so that the test method names are on their own line without modifiers, we can read a specification of our class simply by folding up the bodies of our test methods:
class JoinTest { joiningEmptyListReturnsEmptyString() { joiningListOfOneStringReturnsThatString() { joiningListOfStringsConcatenatesThoseStringsSeparatedBySeparator() { }
This reflects the view that test driven development is just as much about specification as testing. In fact, you could as far as saying that regression tests are a happy side-effect of TDD. Either way, the intent of each test is now that much clearer.
Topics: Testing