The convention of writing test cases
Functions of test become more and more complicated to understand because of different kinds of coding style by developers. It is hard to maintein the test cases written by other developers as the test codes are difficult to read.
As a result, having a unique convention of how to write the test function is fundamental.
This document contains the following topics:
- How to name a test function
- What is the structure of a test function
- How to make test content more understandable
- Libraries for testing
How to name a test function
According to 7 popular unit test naming which gives different opinions of how to name unit test function.
As a combination of such suggestion, I prefer to use:
To begin with:
testis prefixed of all test functions, and it is often considered redundant, however, it helps to search all the test function in a test class
functionNameis used in camel case and is the target function that aims to test
WHENis to describe the different input and given condition for the target function.
THEN: to describe the expectation behavior after invoking the target function under the
Assuming that a class,
AccountService, containing a public function
Then the unit test of
AccountService should look like following:
When to separate words with underscore _?
It depends on whether a words should be classified as a group that specified one thing or an item and mostly it should be composed by an adjective and a noun.
_completedRequest_represents for a completed http request
_throw_AlreadyExistAccountExceptionmeans that will throw a specified exception class
_accountId_is a certain property of a class
What is the structure of a test function
As mentioned in Clean Code #ch9, a test function is mostly composed by 3 parts: Prepare, Operation, Check; Then also are considered as another terms Given, When, Then for BDD.
The preparation before the target function starts
Usually, the pre-test condition such as fake data in database or mock function should be defined prior to the preparation.
Invoke the target function (with parameters) you want to test.
Finally, is a serial of validation action and it means checking what happens after calling the target function, for example, checking whether data set into the database or whether the core component is invoked.
- Notably, sometimes Given is not necessary when we don't have any assumption or pre-test condition. Especially for some static util funciton.
How to make test content more understandable
The test code should be readable rather than following the code structure. If you even can't understand what a test is going on, then you no longer to be able to maintain this test.
There are 3 tips of making the test easier to read for other developers:
1. extract the behavior:
Most of time, we don't care much about the test details. So it'd better to extract the main behaviors into a function with enough narrativity naming. It is helpful to let others understand the purpose at the first moment they look into the test function:
The test structure is more clear when the details are hidden in the other more function.
2. One test function is for one test purpose
Don't mix up different purposes within one test function, because it betray the naming design rule. And it will lead to no recognization of what situation cause a fail test.
3. Separating the Give, When, Then with enough vertical distance.
It is a good way to insert the comment line separating these 3 parts, like our sample code.
Libraries for testing
For MOCK function purpose, the Mockito is the best choice to do function isolation.
PowerMockito is NOT ADVICED TO USE although it is also another powerful test framework. Because of mock private functions does break the code design and result in useless verification when the private function is changed.
For do VERIFICATION, AssertJ is also the good for verifying behavior. It has completeness and fluent-design APIs, moreover, the usage is very intuitive. See the article for more information about the difference between several assertion libraries.