Phil Karlton once said:

“There are only two hard things in Computer Science: cache invalidation and naming things.”

Absolutely true. Today, most of us are pretty conscious about giving things the right name, like classes, methods, fields and local variables, and naming things correctly is a vital part of any code review.

While this is a good thing, we tend to forget to apply the same standards to our test code.

Let’s write some production code…

Consider the following class that we want to test:

…and then test it!

Let’s write a unit test that verifies the behaviour. I’m using AssertJ here, which I highly recommend for readable assertions:

Nice! This test() method verifies the behaviour correctly.

Now, what if the production code would change and the test would fail? That would require me to:

  • Explicitly associate the test method to the “greet” method in the GreetingService;
  • Find out what goes wrong;
  • And more importantly: I have to dig into the implementation of the test method to find out what is being tested, so I will get a hint on what part of the production code might be broken!

Is this a contrived example? Well, no, I encounter this in real-world applications frequently.

So, let’s see if we can name the test in such a way it will be clearer what expected behaviour is actually failing!

Step 1: include the class name

I see this pattern frequently in classes under test with only one public method.

Really, it still doesn’t tell you anything, right?

Except the unit test is working on the GreetingService class, which was already pretty obvious.

So, let’s make it a little more specific.

Step 2: reference the method name

This is a little better. At least, now I understand what method fails.

But still, I have no idea what part of the behaviour is broken without looking at the internals of the test implementation.

So, let’s reflect the expected behaviour of the method in the test method name:

Step 3: specify expected behaviour, not implementation details

Ok, now the expectations of the test are clearly defined in the test method name: when greeting is called with username then response should be hello with the user name.

The most important thing here is that:

I don’t need to delve into the test method body to figure out what’s wrong with the production code. It just TELLS ME by its name what expected behaviour fails.

Pretty specific defined behaviour, right? Yes, but it’s still a bit unreadable. Now, this is a matter of taste, but I like Snake Case instead of camelCase to make things more readable:

Step 4: make things readable

Very good. But, when you look at the production code, there are two separate behaviours to test:

  • The greet method returns a “Hello,” prefix
  • The prefix is followed by the username

The behaviour of the method has two aspects, not one. To find out what part of the behaviour is wrong, it is better to split the behaviour assertion into two tests:

Step 5: test one thing at a time

This way, we test two different aspects of the behaviour in two separate test methods, mirroring the behaviour of the code under test:

  • The greet method returns a “Hello,” prefix
  • The prefix is followed by the username

This way, if a test fails, we can immediately find out what part of the behaviour breaks, because the test method name clearly echoes what part of the production code fails, without having to look at the implementation of the test method.

Summary

Correctly naming test methods, and testing one thing at a time, will help you tremendously in finding out what is wrong with your production code, without the need to inspect the implementation of your test methods. So:

  •  Specify specific behaviour in your test method names;
  • Not the implementation details;
  • And make sure you Test one thing at a time.

This way, refactoring and debugging your production code becomes much easier!

If you want to look at some examples I explained here, go to the GitHub project at https://github.com/MichelSchudel/test-naming-demo