When it comes to writing great unit tests, the unit testing method naming convention is one of the best ways to ensure that your tests are easy to read and understand. By following the proper convention, you can write tests that are easy to decipher while reducing the code you need to write and maintain.
This article explores some of the best unit test method naming conventions and how you can implement them in your projects.
So, what’s the preferred unit test method naming convention?
The one that many people use is
UnitOfWork_ExpectedBehavior_ScenarioUnderTest, or something very similar to this.
When we look at our naming convention, it is built from 3 parts:
1. UnitOfWork name could be as simple as a method name (if that is the whole unit of work) or more abstract if it is a use case that uses multiple methods or classes such as UserLogin or RemoveUser.
2. ExpectedBehavior is the result we expect to occur after executing the unit of work.
3. ScenarioUnderTest represents a scenario or circumstances under which the unit of work is being executed.
But that’s just one unit testing naming convention. If you want to see what other options are available to you so you can pick the one that suits you best (but also what to avoid), then keep reading!
Why is it important to have a convention?
Of course, you have heard about the importance of unit tests in software development, but what about test method naming convention? This is a little less talked about, but still, it’s important.
Let me tell you why.
A unit test method name is the first thing, anyone, trying to understand your code will read. It is important to write descriptive method names that help readers quickly identify the purpose of a test case. These method names communicate what the code does. A name should be concise, unambiguous, and consistent.
The name should accurately describe the intent of the code. Method names should be as long as is necessary to fully describe the action being performed.
Many people have a hard time following the convention, but it is not that tricky. The same can be said for naming classes, variables, and properties. Following a naming convention will make your code more readable and thus easier to understand and maintain.
It’s all about saving time
Imagine this scenario: you are working on a feature. You make some changes, run your unit tests after that and get a failure. If you do not know what you broke just by looking at the test name, you need to read what the test does. Why does this matter? Because every time you must go to the failing test to read test code, you lose precious time. The feedback cycle lengthens, and you are breaking the momentum you have.
Instead, you can try to code using fast feedback. When you run unit tests and get a failure, you want to understand what you broke. And you want to do this without reading the test code. The test name alone should give you the information about what is being tested to know what you broke.
What are some popular naming conventions for unit tests?
When it comes to naming unit test methods, many developer groups have their conventions. Some use the word “Test”, while others use a combination of words, numbers, and letters. Some use sentence-style capitalization while others use camel case. Some use verb-based names, and others use noun-based names. There are a lot of conventions that can be used.
However, there are a few things to consider when picking your method naming convention. To make your test methods easier to read and understand, you should use a method naming convention that makes sense to you and the team. And use it consistently.
Let’s go through the most common unit testing method naming convention used in C#.
UnitOfWork_StateUnderTest_ExpectedBehavior
This is probably the most popular naming pattern. Roy Osherove introduced this convention in his book called The Art of Unit Testing. It has three parts:
- UnitOfWork represents a unit of work, that is, the method or class that’s being tested.
- StateUnderTest – this is the scenario we are testing
- ExpectedBehavior – this is the expected outcome under which the test will pass. If the test fails, this means that the current code doesn’t match what the test expects.
The examples of this convention are:
OrderRepository_WhenAllFieldsArePopulated_SavesDataToDatabase()
Invoice_WhenQuantityIsMissing_CannotBeProcessed()
One disadvantage of this convention is that method or class name being tested is written in the test itself. When you later refactor the method and change its name, you need to remember to change tests as well. But I think that’s a fair trade-off since the test name clearly states what’s being tested.
UnitOfWork_ExpectedBehavior_ScenarioUnderTest
This is a similar convention as the previous one. The only difference is that the 2nd and the 3rd part are reversed. This is done for the test name to read more like a natural sentence.
The previous examples using this convention:
OrderRepository_saves_data_to_database_when_all_fields_are_populated()
Invoice_cannot_be_processed_when_quantity_is_missing()
As you can see, you can also put all words in lowercase and separate them with an underscore.
Should naming standard
In this convention, every test case begins with Should. And the class name (and the name of the test file) in this case identify what’s being tested.
Example:
public class OrderRepositoryTests
{
[Fact]
public void Should_Save_Data_To_Database_When_All_Fields_Are_Populated() { }
}
test_Feature
This convention adds the “test” prefix to every name. Some say that this is useful; the test name sound more natural. Others (me included) think that adding this prefix is not needed since you can easily identify all the tests in the Test Explorer.
Example:
test_InvoiceCannotBeProcessed_WhenQuantityIsMissing()
When_Condition_Expect_Result
In this convention, the test name starts with “When”, following the condition or scenario being tested. After that, comes “Expect” following with the expected result.
Some examples:
When_AllFieldsArePopulated_Expect_OrderRepositorySavesDataToDatabase()
When_QuantityIsMissing_Expect_InvoiceCannotBeProcessed()
Given_When_Then
This convention is very popular in the Behavior-Driven Development process. The test is broken into three parts:
Given_UserTriesToSaveInvoice_When_AllFieldsArePopulated_Then_DataIsSavedToDatabase()
The focus of this convention is on describing the behavior of the system.
Some test method names to avoid
This is in no way a complete list, but there are some common test method names that you should avoid in your unit tests. Why? Because they are hard to read and understand. They are not self-explanatory and make your tests harder to understand.
TestXX
The example of this bad naming convention are the tests that only have the word “Test” and the number of the test; Test001, Test002, Test003… These names don’t contain any information about what’s being tested.
Test_FeatureXX
An example of this convention is “Test_OrderRepository001“. This is similar to the previous example. the only advantage is that you can understand what feature is being tested. But everything else is a mystery. Therefore this convention should be also avoided.
How to name a test class
Some would argue that test class names are not as important as the code inside them. But, besides being a good habit, it’s often helpful to come up with a name for your test that makes it obvious what’s being tested.
Test class naming convention usually follows the naming convention of the class being tested, e.g., the class under test is “Order” the corresponding test class will be “OrderTests“. When in doubt, it is a good practice to model the test class name after the production class it is testing. The reason the class ends with plural Tests, it’s because usually every test class usually contains multiple tests.
How to name a test project
Is there a naming convention for test projects? It’s one of those frequently asked questions that many developers have asked. The answer is yes, and the same rules apply to naming any other project. It needs to be meaningful enough to cover all the classes it contains.
There are different types of test projects that must be named differently.
- Unit test project – If you only have unit tests as part of your solution, then name this project ProjectBeingTested.Tests. An example of this is CryptoApplication.Tests. If there are other types of tests as well, then prefix with “.UnitTests”.
- Integration test project – if you have an integration test project, make sure you add a prefix “.IntegrationTests”.
- UI test project – similar to above, add “.UITests”.
The risks of not having a convention
It’s not uncommon to see code that doesn’t follow a set naming convention for unit test methods. This means that it is a lot harder to understand what the test is doing, which in turn makes it harder to tell if the test is written correctly or not.
This is especially true for people not familiar with the project or technology stack and trying to get to grips with what is going on. As a result, it’s important to have a naming convention for unit test methods and ensure that it is followed throughout the project.
If your method names aren’t consistent, it will also be harder for you to understand the tests after returning to them in the future. And you’re going to make the lives of other developers a lot harder. Do you really want to make the life of your co-worker miserable? I’m pretty certain you don’t.
So take the time to make your code more purposeful. And treat your tests the same way you treat your production code. You’ll be glad you did.
Conclusion
A naming convention is so important if you want to save time and be sure that you are testing the right things, which can be expected through the name convention. Keep this in your mind and always give proper and detailed names to the methods.