Naming Unit Tests is hard but also very important to get it right. Other programmers and yourself in the future should understand what the test is about only by reading its name. So what is the best Unit Test Naming Convention in C to get this job done?
As a general rule the Unit Test Naming Convention of your choice should focus on the behavior of the system and not on implementation details like the name of the method under test.
Let’s examine some Unit Test Naming Conventions and their pros and cons. By the end of this article you will (hopefully) know which one is the best for you.
How Do You Name a Unit Test?
There are several Naming Conventions which are used by programmers all over the world. Some of them focus on the behaviour of the software while others focus on the implementation. There are also different styles of writing, CamelCase, CamelCase_with_Underscores, underscores_only, etc.
When naming a Unit Test you should keep in mind who will be the reader and what his intention may be. A poorly named Unit Test may slow down the programmer that wants to understand what exactly is tested. This programmer could be a fellow colleague, or it could be even you in the future, when you have forgotten what you did in the first place.
Following is a brief overview of the Unit Test Naming Conventions with an example:
Naming Convention | CamelCase / Underscore | Focus On |
---|---|---|
Feature to be tested | LoginFailsWithWrongPassword login_fails_with_wrong_password | Behavior |
Method State Behavior | Login_WrongPassword_LoginFails login__wrong_password__login_fails | Implementation |
Method Behaviour State | Login_LoginFails_WrongPassword login__login_fails__wrong_password | Implementation |
Should When | Should_FailLogin_When_PasswordIsWrong should__fail_login__when__password_is_wrong | Behavior |
When Expect | When_PasswordIsWrong_Expect_LoginFails when__password_is_wrong__expect__login_fails | Behavior |
Given When Then | Given_PasswordIsWrong_When_Login_Then_LoginFails given__password_is_wrong__when__login__then__login_fails | Behavior (BDD) |
Should I Use the Test Prefix for Unit Test Names?
You will find a lot Unit Tests that have a test prefix in their name, e.g. testLoginFailsWithPassword. There is nothing wrong with this approach and in some Frameworks (like pytest for Python) it is even mandatory. I personally think that it is redundant and it is not necessary for the C and C++ Unit Testing Frameworks which you can use for C Programming.
What Differs C From Other Languages in Unit Test Naming Conventions?
On the whole there is no real difference between C and other languages in terms of naming conventions. These are more a universal principle which you should consider in every Unit Testing Scenario, whatever the language may be.
What Naming Convention Should Be Used for Method Names?
We will get a short description and some pros and cons of each Unit Test Naming Convention in the following paragraphs.
Feature to be tested
A simple and effective strategy is to name the test after the feature to be tested. It decouples the test from the implementation and focuses on the behaviour of the system.
Example: LoginFailsWithWrongPassword
Pro: We have a clear english sentence which states the purpose of this test and is easily readable. The con is that this can get rather long and sometimes it is hard to come up with a good, short name. But in my opinion it is worth the effort.
Method State Behavior
This one and the next are very common Unit Test Naming Conventions and they are even used in some books. It is for example used in the great “The Art Of Unit Testing”, by Roy Osherove.
The structure is as follows: First the method name is specified, then the target state which is checked and then the behavior that this state leads to.
Example: Login_WrongPassword_LoginFails
In this example, Login is the method under test, WrongPassword is the target state and LoginFails is the behaviour that the wrong password leads to.
The pros are that you exactly see what the purpose of a method is and what happens in a given state.
However, the big con is that you focus on the implementation. If you change the method name (e.g. during refactoring) than you would have to change the test name, too. This is additional work and it is highly like to be forgotten anyway. This would lead to a situation where you would not understand the purpose of the test anymore.
Method Behaviour State
As I mentioned in the last section, this style is also very common. It is also very similar because it only switches the order of the last two parts. For this reason it shares the same pros and cons.
The structure here is method name, then the behaviour the state leads to and then the state.
Example: Login_LoginFails_WrongPassword
Here again Login is the method under test, but now ist is the behaviour LoginFails and then the target state WrongPassword which leads to the behaiour.
Should When
In the Java world, there is a “movement” that names the test classes with a Should prefix. The class itself is the name of the feature, like LoginProviderShould and the tests are named after each feature that the login provider should be capable of, like e.g. LoginProviderShould(failLogingWithWrongPassword).
In this case, however, we use the syntax Should_Behavior_When_State which is a different twist on should. It looks something like this:
Example: Should_FailLogin_When_PasswordIsWrong
In this case, FailLogin is the behaviour and PasswordIsWrong is the state.
When Expect
The When Expect syntax is the reverse of Should When.
Example: When_PasswordIsWrong_Expect_LoginFails
So here we first describe what the state is, PasswordIsWrong, and then tell the behaviour which results from it.
Given When Then
Besides the Test Driven Development (TDD) methodology there is another one called Behavior Driven Development (BDD) which can be used on its own or in conjunction with TDD. Acceptance Criteria for a scenario (which is part of a feature) in BDD is described in the Given When Then notation.
You could also apply this notation for your unit tests. It gives a clear structure and describes behavior to the reader. On the con side it could imply that this is a BDD test and not a Unit Test which could lead to confusion.
Example: Given_PasswordIsWrong_When_Login_Then_LoginFails
This is the condensed version of:
Scenario: Login
- Given the Password is wrong
- When you try to login
- Then the login fails
The decision which Unit Test Naming Convention you use is up to you. But keep in mind: Be consistent in your project and only use one Naming Convention instead of mixing them, and always use a convention as any Unit Test Naming Convention is better than not using any at all.