Writing Clean Tests – Beware of Magic

It is pretty hard to figure out a good definition for clean code because everyone of us has our own definition for the word clean. However, there is one definition which seems to be universal:

Clean code is easy to read.

This might come as a surprise to some of you, but I think that this definition applies to test code as well. It is in our best interests to make our tests as readable as possible because:

If our tests are easy to read, it is easy to understand how our code works.

If our tests are easy to read, it is easy to find the problem if a test fails (without using a debugger).

It isn’t hard to write clean tests, but it takes a lot of practice, and that is why so many developers are struggling with it.

I have struggled with this too, and that is why I decided to share my findings with you.

This is the third part of my tutorial which describes how we can write clean tests. This time we will learn two techniques which can be used to remove magic numbers from our tests.

Constants to the Rescue

We use constants in our code because without constants our code would be littered with magic numbers. Using magic numbers has two consequences:

Our code is hard to read because magic numbers are just values without meaning.

Our code is hard to maintain because if we have to change the value of a magic number, we have to find all occurrences of that magic number and update everyone of them.

In other words,

Constants help us to replace magic numbers with something that describes the reason of its existence.

Constants make our code easier to maintain because if the value of a constant changes, we have to make that change only to one place.

If we think about the magic numbers found from our test cases, we notice that they can be divided into two groups:

Magic numbers which are relevant to a single test class. A typical example of this kind of magic number is the property value of an object which created in a test method. We should declare these constants in the test class.

Magic numbers which are relevant to multiple test classes. A good example of this kind of magic number is the content type of a request processed by a Spring MVC controller. We should add these constants to a non-instantiable class.

Let’s take a closer look at both situations.

Declaring Constants in the Test Class

So, why should we declare some constants in our test class?

After all, if we think about the benefits of using constants, the first thing that comes to mind is that we should eliminate magic numbers from our tests by creating classes which contains the constants used in our tests. For example, we could create a TodoConstants class which contains the constants used in the TodoControllerTest, TodoCrudServiceTest, and TodoTest classes.

This is a bad idea.

Although it is sometimes wise to share data in this way, we shouldn’t make this decision lightly because most of the time our only motivation to introduce constants in our tests is to avoid typos and magic numbers.

Also, if the magic numbers are relevant only to the a single test class, it makes no sense to introduce this kind of dependency to our tests just because we want to minimize the number of created constants.

In my opinion, the simplest way to deal with this kind of situation is to declare constants in the test class.

Let’s find out how we can improve the unit test described in the previous part of this tutorial. That unit test is written to test the registerNewUserAccount() method of the RepositoryUserService class, and it verifies that this method is working correctly when a new user account is created by using a social sign provider and a unique email address.

The problem is that this test case uses magic numbers when it creates a new RegistrationForm object, configures the behavior of the UserRepository mock, verifies that information of the returned User object is correct, and verifies that the correct method methods of the UserRepository mock are called in the tested service method.

After we have removed these magic numbers by declaring constants in our test class, the source code of our test looks as follows:

This example demonstrates that declaring constants in the test class has three benefits:

Our test case is easier to read because the magic numbers are replaced with constants which are named properly.

Our test case is easier to maintain because we can change the values of constants without making any changes to the actual test case.

It is easier to write new tests for the registerNewUserAccount() method of the RepositoryUserService class because we can use constants instead of magic numbers. This means that we don’t have to worry about typos.

However, sometimes our tests use magic numbers which are truly relevant to multiple test classes. Let’s find out how we can deal with this situation.

Adding Constants to a Non-Instantiable Class

If the constant is relevant for multiple test classes, it makes no sense to declare the constant in every test class which uses it. Let’s take a look at one situation where it makes sense to add constant to a non-instantiable class.

Let’s assume that we have to write two unit tests for a REST API:

The first unit test ensures that we cannot add an empty todo entry to the database.

The second unit test ensures that we cannot add an empty note to the database.

These unit tests use the Spring MVC Test framework. If you are not familiar with it, you might want to take a look at mySpring MVC Test tutorial.

Both of these test classes declare a constant called APPLICATION_JSON_UTF8. This constant specifies the content type and the character set of the request. Also, it is clear that we need this constant in every test class which contains tests for our controller methods.

Does this mean that we should declare this constant in every such test class?

No!

We should move this constant to a non-instantiable class because of two reasons:

It is relevant to multiple test classes.

Moving it to a separate class makes it easier for us to write new tests for our controller methods and maintain our existing tests.

Let’s create a final WebTestConstants class, move the APPLICATION_JSON_UTF8 constant to that class, and add a private constructor to the created class.

We have just removed duplicate code from our test classes and reduced the effort required to write new tests for our controllers. Pretty cool, huh?

If we change the value of a constant which is added to a constants class, this change effects to every test case which uses this constant. That is why we should minimize the number of constants which are added to a constants class.

Summary

We have now learned that constants can help us to write clean tests, and reduce the effort required to write new tests and maintain our existing tests. There are a couple of things which we should remember when we put the advice given in this blog post to practice:

We shouldn’t introduce new constants without figuring out what we want to achieve with that constant. The reality is often a lot more complex than the examples of this blog post. If we write code on autopilot, the odds are that we will miss the best solution to the problem at hand.

Newsletter

Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

Email address:

Join Us

With 1,240,600 monthly unique visitors and over 500 authors we are placed among the top Java related sites around. Constantly being on the lookout for partners; we encourage you to join us. So If you have a blog with unique and interesting content then you should check out our JCG partners program. You can also be a guest writer for Java Code Geeks and hone your writing skills!

Disclaimer

All trademarks and registered trademarks appearing on Examples Java Code Geeks are the property of their respective owners. Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries. Examples Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.