Core Java

Getting JUnit Test Names Right

Finding good names is one of the challanges of crafting software. And you need to find them all the time and for everything – classes, methods, variables, just to name a few. But what makes a name a good name? To quote Oncle Bob: ‘Three things: Readability, readability, and readability!’ Which he defines later one by clarity, simplicity and density of expression1.

Though this makes sense to me, I watch myself struggling in particular with test method naming a bit. To better unterstand of what I am talking about, one needs to know that I write my code test driven. And doing this for a while I changed my focus of work gradually from the unit under test more to the test itself. This is probably because I like to think of a test case as a living specification and quality assurance in one piece and hence that it is vitally important2.

So whenever a test breaks, ideally I would be able to recognize at a glance what specification was broken and why. And the best way to achieve this seems to be by finding an expressive test name, because this is the first information displayed in the reporting view:

specification

Seen from this angle I am not always happy with what shows up in this view and so I spent a bit of time on research to see what school of thought might be helpful. Unfortunately most of the results I found were somewhat dated and – less surprising – the opinions on this topic are divided. This post represents my reflections based on those findings and a bit of personal experience.

Tests per Method- or Behavior Test-Names?

In its pure form the tests per method approach is often provided by tools that e.g. generate a single test stub after the fact. In case you have a class Foo with the method bar the generated method would be called testBar. I was always sceptical about the usefulness of such a development style or naming convention and would have argued like this quote from an old JavaRanch thread: ‘you shouldn’t think about it as testing methods at all, you should think about it as testing behavior of the class. Consequently, I like my test method names to communicate the expected behavior’3.

Interestingly enough I am about to change my opinion a bit on that one. The idea of communicating the ‘behavior’ as stated above requires to find a concise name that expresses this ‘behavior’ comprehensively. But then the term behavior implies a transition from one state to another conducted by an action, or denoted in BDD terms for example a Given-When-Then pattern. Honestly, I do not think that it is in general a good idea to put all this information in a single name4:

@Test
public void
  givenIsVisibleAndEnabledWhenClickThenListenerIsNotified() {}
@Test
public void
  givenIsVisibleAndNotEnabledWhenClickThenListenerIsNotNotified() {}
@Test
public void
  givenIsNotVisibleAndEnabledWhenClickThenListenerIsNotNotified() {}

Maybe its just a question of taste but from my experience this approach often lacks readability due to the absence of simplicity and/or clarity no matter what kind of format style I chose. Furthermore such overloaded names tend to have the same problem as comments – the names get easily out of date as the content evolves. Because of this I would rather like to go with the BUILD-OPERATE-CHECK5 pattern instead. This would allow to split up the the phases into separate sub method names placed withing a single test:

@Test
public void testNameHasStillToBeFound() {
  // do what is needed to match precondition
  givenIsVisibleAndEnabled();

  // execute the transition
  whenClick();

  // verify the expected outcome
  thenListenerIsNotified();
}

Unfortunately this leads us to where we started. But if you take a closer look at the examples above, all the methods group around a common denominator. They all belong to the same action that fires the transition. In our case the click event. Considering that from the development process point of view I regard a test case more important than the unit under test, one could interprete this as a sign to reflect the action by an appropriate method name in the unit under development6.

So for the sake of example assume we have a ClickAction that wraps around a UI control. And introducing a method called ClickAction#execute() might seem appropriate to us, given the situation above. As simplicity matters we could use that name also for the test method that represents the transition from the default state of the ClickAction – control construct via ClickAction#execute():

class ClickActionTest {

  @Test
  public void execute() {
    Control control = mock( Control.class );
    ClickAction clickAction = new ClickAction( control );

    clickAction.execute();

    verify( control ).notifyListeners(...)
  }
}

To keep things simple the next test name may mention only the state information that is important as it differs from the default and leads to another outcome:

class ClickActionTest {

  [...]

  @Test
  public void executeOnDisabledControl() {
    Control control = mock( Control.class );
    when( control.isEnabled() ).thenReturn( false );
    ClickAction clickAction = new ClickAction( control );

    clickAction.execute();

    verify( control, never() ).notifyListeners(...)
  }

  @Test
  public void executeOnInvisibleControl() {
  [...]
}

As you can see, this approach results in a set of test names that technically spoken represents a variety of the ‘tests per method’ pattern – but not for completely bad reasons as I think. Given the context I consider this naming pattern is simple, clear and expressive up to one point:

The expected test outcome is still not mentioned at all. On first glance this looks unsatisfactory, but from my current point of view I am willing to accept this as a sound trade off. Especially as the cause for a failing test is usually also shown in the JUnit reporting view. Because of this that problem can be handled by providing meaningful test failures7.

Conclusion

Actually I am using the test naming pattern described above for some time now. So far it works out not too bad. In particular when working with pretty small units as I usually do, there is little room for misinterpretation. However this approach does not match all cases and sometimes it simply feels better and is still readable enough to mention the outcome. I will not harping on about principles here and maybe I am getting it all wrong. So I would be happy for any pointers to more elaborated approaches that you might be aware of to broaden my point of view.

  1. Robert C. Martin about clean tests, Clean Code, Chapter 9 Unit Tests
  2. What would be worse: losing the unit under test or the test case? With a good test case restoring the unit should be most of the time straightforward, however vice versa you could easily miss out one of the corner cases that were specified in the lost test case
  3. Naming convention for methods with JUnit, Naming convention for methods with JUnit
  4. To prevent misunderstandings: BDD does nothing the like and comes with its own testing framework. I just mentioned it here as the term ‘behavior’ seems to suggest it and the term ‘givenWhenThen’ floads around in many discussions about test names. However you find actually proposals like Roy Osherove’s naming conventions labelled ‘UnitOfWork_StateUnderTest_ExpectedBehavior’ that still seem to be well accepted albeit the post has seen most of the days of the last decade
  5. Robert C. Martin, Clean Code, Chapter 9, Clean Tests
  6. Or even to extract the whole functionality into a separate class. But this case is described in my post More Units with MoreUnit
  7. Which is probably a topic of its own and as I have to come to an end I leave it at that way!
Reference: Getting JUnit Test Names Right from our JCG partner Frank Appel at the Code Affine blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button