You run your unit tests, and get a failure. How many times have you had to dig through the test code to try to understand what it’s complaining about?
Why does this matter? Because every time you have to read test code, you lose precious time. The feedback cycle lengthens, and you’re breaking your stride.
Instead, I try to code using fast feedback. When I run unit tests and get a failure, I want to understand what I broke. And I want to do this without reading the test code. The test name alone can give you the information you need.
In this post, I’ll describe the unit test naming pattern that can give you feedback from the name alone.
What’s in a name? — Romeo and Juliet, Act 2, Scene 2
Good Test Naming: Three Elements
Instead, let’s put more information into the test name. When a test fails, I want to know three things:
- What operation are we testing;
- Under what circumstances; and
- What is the expected result?
Disclosure: The book links below are affiliate links. If you buy anything, I earn a commission, at no extra cost to you.
Roy Osherove, author of The Art of Unit Testing, provides a good unit test naming style that incorporates these three elements. Here’s how he describe it in a blog post Naming standards for unit tests:
In behavior-driven vocabulary, the same three parts are expressed as given/when/then, just in a different order.
Applying This Naming to XCTest
I have adopted this unit test naming convention, with slight changes:
- Apple’s XCTest framework still lacks a way to annotate test methods. So we have to start with a test prefix.
- Then I describe the “unit of work.”
- I usually begin the “state under test” with the prefix with.
- I usually begin the “expected behavior” with the prefix should.
All told, I apply my modifications to Roy Osherove’s template to get test names that look like this:
It may look odd to combine camel casing with underscores—a sort of “mutant snake camel case”? Some folks can’t stand it! You may object that it goes against Swift naming conventions. “If it’s Swift, a function name must be camel case.” In production code, yes, because a function name should express one idea.
But for a test name, we’re trying to express three things. We often want to test the same operation, but with different inputs. I find the underscores are clear separators, dividing the name into its distinct parts.
My test names don’t follow this template slavishly. If the unit of work is obvious (from the name of the test class), I may omit it. If the expected behavior is obvious, I may omit it. But whether explicit or implied, the three elements must be present without guesswork.
In the next section, let’s look at how we can lean on implied elements.
Should the Test Name Include the Method Name?
How much of all this needs to be explicit? In particular, should the “operation” be a method name? Sometimes. But we need to guard against creating noise.
When any developer… reads test names… to get a handle on a certain area of the codebase, they shouldn’t be tripped up by having to read back implementation details such as method names…. Adding implementation terms just adds noise to the test name. That just makes it more for your eyes to stumble over, keep that stuff out of test names!
In other words, we should aim for test names that describe behavior, not implementation.
Consider the Bowling Game TDD Kata. The object of the exercise is to score a game of bowling. Instead of a test name like
it’s easier to call it
The simpler name assumes more domain knowledge about bowling. If the coders share that knowledge, we can use a simpler name, making the three parts implicit:
- We already know we’re testing how to score a game of bowling.
- A “gutter game” means every roll went in the gutter. The ball didn’t knock down a single pin.
- The score for this scenario is zero.
The rules of bowling are widely known—but not by everyone. For most domains, they’re not even widely known. When in doubt, be explicit and spell out the operation, the input, and the outcome.
Can we really describe the “unit of work” without using the method name? Yes, this can work when testing small types, like something with two non-private methods. When we’re uncomfortable taking this step, it could be that our type is too big. Following the Single Responsibility Principle should result in smaller types.
Then when should we use method names? When the method name adds useful information. Much of what we do as iOS programmers is interact with Apple’s frameworks. A framework means we provide methods for Apple to call. iOS developers build up knowledge about what each method is for, and there are quite a few. For such code, it can make sense to include the method name—or some summary of it—in the test.
Pick a Unit Test Naming Convention That Works for You
Whatever naming style you choose for unit tests, try to communicate the three parts. Choose a balance between verbose and terse that works for your team. You can even change your mind, and rename your tests. Aim for clarity, and keep improving names as you discover better ways to do so.
How do you like to name your unit tests, and under what circumstances? Please share in the comments below.
I encourage you to read Roy Osherove’s book. Don’t say, “I code in Swift, not C#, so this book’s not for me.” This book is full of insights regardless of programming language.