Why Naming Tests Matters?

Why naming tests matters - highlighted photo (tests in ruby)

Do you even care about naming tests? Or maybe you use some random, not-much-telling names for your test methods? At Yumasoft, we treat testing as an inseparable part of software development. It turns out that the tests you write can tell a lot about your software. However, when named carelessly, these tests have much less value. Let’s talk about naming tests properly, so both programmers and business can get more value of them.

Consequences of bad tests’ names

You may think I’m exaggerating here. Why would I care about naming my tests methods? These are only tests… Let’s not waste time on thinking about such unimportant things. However, before we dig more into that, let’s see how typical badly-named tests look like. Below, I’m presenting the types of badly named tests that I see most often. I also used to name my tests like that 🙃

Random names

This is what I like the most:

Rider and unit tests result: Test1, Something1, Test11...

Just random names. Surprisingly, I see that quite often. What does such a list of passing tests tell us? Why do they pass? What do these tests verify? We know nothing about them. We can only see that there are some tests. What they test, how and under what conditions – can’t say 💁‍♂️

Tested object described

This is another type of tests I sometimes encounter. A bit better, yet still far from fully informative:

Naming tests with objects under tests named, for example GetUser_Test1, Login_Test1. Class named UsersServiceTests

Looking at these tests list, we can at least say a few things:

  • there exists a UsersService class which is under tests here
  • UsersService has at least two methods: GetUser and Login
  • under some unknown conditions, GetUser and Login methods probably work

However, we still don’t know what it actually means that these tests pass. Does it mean that login and getting users are well-tested and work correctly? What conditions need to be met so the user can log in? What parameters do we have to provide to GetUser method to use it properly? Again – we can’t say.

Expected outcome described

Let’s go one step further. A bit improved tests might look as follows:

Naming tests with objects under test and expected outcomes named, for example: GetUser_ReturnsUserData

Someone tried to be a bit more descriptive here. That’s good, isn’t it? 😉 Let’s try to see how many things we can say about our codebase now:

  • there exists a UsersService class which is under tests here
  • UsersService has at least two methods: GetUser and Login
  • GetUser method returns user data
  • GetUser might sometimes throw UserNotFoundException
  • Login logs in the user correctly under some conditions
  • Login returns a user token
  • Login might sometimes throw WrongCredentialsException

We already know much more about our codebase! However, notice that we still often use very uncertain words like “sometimes” or “some”. It doesn’t feel we’re sure about these outcomes. We still don’t know under what conditions these tests pass or exceptions are thrown.

Why badly named tests are bad?

I think you already know that at this point. Badly named tests are confusing. They don’t tell us enough about our codebase. One of the goals of tests is to be a live code documentation. But how can they be if they are very undescriptive? How can we know what happens in case such a test fails:

Naming tests and failure of nondescriptive test

What do we know looking at that? Why could this test fail? If there’s a non-technical person looking as this result in a CI system while programmers are not around – how can (s)he tell what’s wrong and how to potentially fix that?

This result tells us nothing more than the Login process does not throw WrongCredentialsException. But we don’t know when it should throw this error. What are the conditions that should be met for this exception to be thrown? Again – we can’t say.

Notice that I used the best from all examples we had so far. What if this test was named Test1() and it failed? Does it mean anything? Is it something serious blocking the release of our app, or we can ignore it? 🤔

I guess you now see very well what I mean by badly named tests. I hope you also understand – and agree 🙂 – that such tests’ names are bad.

Fortunately, we all here write tests, right? 😉 So, if we are already putting some effort in creating tests, let’s put a bit more to make them informative and useful for others.

Naming tests done well

There are a lot of unit tests naming conventions. You can read about them in many great articles like this one. There’s a lot of discussion around naming tests conventions.

However, independently of which naming strategy you choose, I think a well named test should tell someone who reads its name the following things:

  • what is tested (class name)
  • which part of it is tested (method name)
  • what is the expected result
  • what are the conditions for the expected result

Many of tests naming conventions fulfil these 4 requirements.

Let’s come back to our last example of badly named tests (but still its best version):

Tests named with objects under test and expected outcomes named, for example: GetUser_ReturnsUserData

Let’s use one of the naming conventions I like:

MethodName_Should_ExpectedResult_When_Conditions

Applying this to our tests, the final result is as follows:

Well named tests, for example GetUser_Should_ReturnUserData_When_ExistingUserIdProvided

Now, for each test, we can see what is tested (UsersService), which part of it (e.g. Login method), what’s the expected result (e.g. ReturnUserToken) and under what conditions (e.g. CorrectUsernameAndPasswordProvided). This is very descriptive and valuable. Now, when something goes wrong:

One test failing from all properly named. Thanks to its descriptiveness, it's easy to see what's wrong

We know a lot more than before. We can easily see that when wrong credentials are provided, the WrongCredentialsException is not thrown (while it should). It makes it easier to judge whether this is blocking for the release of our app or not. We probably don’t want to let users login with incorrect credentials 🙂

Another, very important factor for naming your tests well is that the whole team agrees on one naming convention. I think it’s even more important than choosing a particular naming convention. Choose whatever suits you and your team. There are a lot of options, but in the end it doesn’t really matter which one you agree on. Just stick to it and make sure it delivers all value you need.

How naming tests well can help the programmers

Correctly and descriptively named tests can help you as a programmer. Imagine that you are about to introduce a change in UsersService, but you have no idea how it works. The first thing I do in such cases is to open a corresponding tests file and scan all unit tests.

First, I expect that the tests file is named UsersServiceTests, because my team follows a common naming convention. Thanks to that, I can immediately open this class in my IDE and quickly scan all unit tests names:

Quickly scanning well-named tests in a test class as in IDE

This tells me a lot about the UsersService. If I want to see only how Login method works, I can easily filter out all tests with names starting with “Login”. Again – thanks to following the naming convention.

The next thing is that when you start making changes to the production code of UsersService and one of the tests fails, you know what’s wrong very quickly.

Another advantage of naming tests properly is when you are adding new tests. If you’re obliged to follow a descriptive tests naming convention, you need to think very well what your new code under tests should do and under what conditions. This makes your production code more structured and well-thought. Just give it a try, especially if you use TDD. I often start my TDD session with writing empty tests named correctly. This gives me many ideas of the production code I’m going to write straight after.

How naming tests well can help the business

I think I don’t need to explain that to you anymore. However, remember that your tests might be useful for other people than programmers. All non-technical people involved in the project can have a great use of the tests if you name them correctly.

I hope that your tests are executed as part of a CI process you use for your app deployment. As I wrote before, imagine having a late Friday release of your app. As a programmer, you’re the last one to commit this one last bug fix, and you go home. The project manager stays alone, waiting for the CI build to finish, so he can accept and deploy the new version of the app. But then, one of the tests fails. If your tests are named well, he will be able to easily judge whether this is blocking the deployment or not. I think that gives a lot of value to the business.

In case of some applications, where classes/services are created close to the domain of the app, business people can also explore the set of tests for a given service to grasp an idea of how it works and why it works as it does. Similarly, when you explore the tests class in your IDE. This wouldn’t be possible in every project, but it might also become a benefit of well-named tests in some cases.

Summary

I hope that after reading this article, you know why naming tests matters. Giving your test a descriptive name is a small effort, but it brings huge benefits. Both to your fellow programmers, but also to non-technical, so-called “business people”.

5 1 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x