Write JUnit tests that read like documentation

Wouldn't it be cool if everyone could use tests to understand our systems?

Writing good documentation is hard.

Test writing enthusiasts like to point at their suites of tests and call them the “living documentation” of the system. But reading tests is a terrible way of trying to understand the behaviour of a system. Usually written in the same programming language as the system, they're difficult to decode and don't answer the fundamental questions that documentation should answer for the reader

  • How does it work?
  • What can it do for me?
  • How can I make it do that?

Simple JUnit tests are terrible documentation that is, unless you follow a few simple rules...

Use the Test class name suffix convention

To name a test class, take the name of the class under test and add “Test” on the end.

e.g. MovieTitleMatcherTest contains tests for MovieTitleMatcher

This instantly adds context to the tests, connecting them to where the behaviour is implemented. So for any given class, it's easy to find the tests that verify it's behaviour and vice versa.

Integration and system tests can also be named after similar higher-level prod-code abstractions (MegaMovieMarket will have it's behaviour tested and documented by MegaMovieMarketTest) in fact, the lack of a viable candidate to attach this kind of test class to, might indicate that a key abstraction is missing.

Write test names as natural language sentences

Ask yourself how you would describe the behaviour being tested to someone simply and succinctly. Chances are, that sentence would make a good test name. Use natural language with an active voice.

public class MegaMovieMarketTest {
  @Test public void findsMovies()
  @Test public void sellsMovies()
  @Test public void buysMovies()

public class MovieFinderTest {
  @Test public void findsMoviesByPartialTitle()
  @Test public void findsNoMoviesWhenNoMovieTitleContainsThePartialTitle()
  @Test public void findsMoviesReleasedWithinAGivenSpanOfYears()
  @Test public void findsNoMoviesWhenNoneWereReleasedWithinAGivenSpanOfYears()

public class MovieTitleMatcherTest {
  @Test public void matchesMoviesWithTitlesContainingTheSearchText()
  @Test public void isFalseOtherwise()

If you spend most of the day diving in code, the simple sentences are easy to decrypt.

“Movie title matcher, matches movies with titles containing the search text”

For non-developers, explicitly expanding the camel casing into sentences and removing the surrounding programming language noise makes everything a little easier to parse..

Mega Movie Market
  Finds Movies
  Sells Movies
  Buys Movies

Movie Finder
  Finds movies by partial title
  Finds no movies when no movie title contains the partial title
  Finds movies released within a given span of years
  Finds no movies when none were released within a given span of years

Movie Title Matcher
  Matches movies with titles containing the search text
  Is false otherwise

Here we have perfectly readable summaries of each unit's behaviour written in a natural language that we can show to testers, support and business analysts.

In fact, the Enso IntelliJ plugin displays a live view of exactly this.

Select quality relevant examples

A common trap developers fall into when writing tests is to think of it as an opportunity to demonstrate how many different combinations and permutations (whether informative or not) they can think up.

It's almost as if more tests == better system

They go for quantity over quality even though a better example or a small change in wording would convey the same amount of information. No one likes to read long lists masquerading as documentation and tests that describe application features are no exception.

Save the reader from having to wade through the superfluous noise. Think of every test you write as a key fact you really need the reader to know about. The more tests you need to describe what a unit does, the more work you force the reader to do to understand what it does, and that's even before they decide if they want to use it.

Don't be afraid of using long descriptive sentences when necessary but also be careful when you find yourself writing them. Ask yourself whether you really need so many words to communicate the purpose of the test.

Tests can be documentation

Writing good documentation is hard but even the humble JUnit test suite can go some way towards becoming “living documentation” by following a few straightforward rules to produce easy-to-read summaries of class, component and application behaviour.

Summaries that you might even be able to give to your stakeholders as evidence that your system does what you say it does.