Expressive Test Names – the Typemock Way
Mark Needham wrote an interesting blog post about his experience handling badly named unit tests and the conclusion of writing descriptive names. I applaud the thought process – this aspect of unit testing is often neglected, and too often we encounter horrendous beasts like TestMethod1(), TestTheModule() or TheTest().
Bluntly put, if you don’t name your tests with care, you are wasting your time. The magic in unit tests is that they pinpoint the root cause of an introduced bug to a simple scenario, saving you expensive debugging time. Written correctly, tests should be simple enough for an experienced developer to understand what went wrong in under 5 minutes (what are we asserting against, what the set up is leading to etc.). However, I would expect any English speaker to get a clue as to what went wrong in just under 5 seconds by reading the test name. In many cases understanding what was being tested or what the expected result was is enough to guide us to a bug fix.
There are various test naming conventions, each with its own merits and weaknesses. Most prefer long, descriptive test names and differ by the way these names are delimited and presented. In Mark’s post he gives one test the name:
public void ShouldNotCloneIdBecauseWeWantANewOneAssignedInTheDatabase()
And one reader comments he prefers delimiting by underscores rather than by camel case, i.e.:
public void Should_not_clone_id_because_we_want_a_new_one_assigned_in_the_database()
(quite a mouthful!). Each is valid and helpful and descriptive, but we do this a bit differently.
Our unit test naming convention at Typemock is borrowed from this post in Roy’s blog a few years ago. Basically, the test name is always comprised of three parts – the method under test, the scenario being tested and the expected result. These are separated by an underscore and camel cased inside each section. For instance, renaming Mark’s test (without understanding anything about his requirements :)) would lead to
public void Clone_OnValidFoo_NewIdIsAssignedInDatabase()
Assuming this name kept Mark’s original intent, we achieved a few things.
- We got rid of several words signifying intent – all the BecauseWeWant is redundant as this is part of the name’s structure. Long names are good. Shorter names that tell the exact same thing are better.
- We created three distinct parts to the test name. This leads the reader’s eye towards what he’s interested in. not sure what part of the system we’re at? the first part of the name should tell you that. Want to figure out what is being tested? the second part will handle that, and so on. This way we spend less time parsing long test names, getting the intent immediately.
- This convention also helps in the common TDD scenario where you test the same thing several times but add another bit of functionality each time. The test writer can simply take the first two parts of the test name and change the third – it doesn’t hide in the middle of the name so it’s easy to do.
Name your tests what you will, but even if you don’t like our naming convention, take this one thing from this post – name your tests with care. It saves time, lends to readability and helps you out whenever something breaks.