days
0
4
hours
1
5
minutes
5
5
seconds
0
6
Naming and testing

Tests need love too

Colin Vipurs
© S&S Media

Testing expert and author Colin Vipurs tells us why you should never name your test “Test1”.

In 1994 I started my undergraduate degree and received the marks for my first programming assignment. I remember it vividly as the comments said “One of the best implementations I have seen”, yet I only scored a barely passing 44%. The reason for this was the lack of evidence of testing, which was unsurprising given that my code had bugs and the calculations it was performing were incorrect. This should have been the time I realised the importance of testing, but unfortunately this didn’t come until a few years later when I started my first programming job.

I was working on a system that would take TV listings in a raw, custom format and convert them, according to various rules, into the format that our many customers wanted. I had a very simple change to make and knew that it would only affect a few customers so I made it and pushed it to production only to find that the change I made affected everybody!

DOWNLOAD IT NOW: Get your copy of Tests Need Love Too here

Vowing to never make this mistake again I wrote a Perl script that would exercise the existing production version of the code and a release candidate over all data for every customer. It would take 5 hours to run but at the end of the run you were guaranteed you hadn’t broken anything. Little did I know that this simple mistake and script would lead me to a lifetime of being test infected.

When I started working with Java I stumbled upon the concept of Unit Testing and immediately fell in love with the ideology, which has been a core part of my development process ever since. Over the years I have redefined how I view a “unit” and have made many, many mistakes in writing tests. I have trained less experienced developers in the art of unit testing and noticed that they would make the same mistakes I did. As part of my job I have also interviewed lots of developers and saw that they were making the same mistakes too.

Naming things

In software development, naming should be easy, it’s something that must be done all the time; files, classes, methods, variables, so why is it so hard to get right? At the time of writing this, a Google search for public void test1() filetype:java yields about 323,000 results!

This is publicly available source code, yet each and every developer could not think of a better name for these tests than “test1”. It is highly unlikely that a class would be named “Class1” or a method “method1” and for the same reason you shouldn’t name a test “test1”.

There are only two hard problems in Computer Science: cache invalidation and naming things. – Phil Karlton

Early on in a developer’s education or career it is taught that something is named so that anyone working on the system can understand its purpose without having to read every line of code. A quick look at some examples from the Java standard classes shows examples like:

Integer::parseInt
StringBuilder::append
Or in standard JavaScript there are examples like:
Array::forEach
JSON::parse

Even without exposure to either language it is easy to understand what the classes or methods above do, but with a test named “test1”, there is no choice but to read the source to understand what’s being tested. It is often said that unit tests can act as executable documentation for a system, but by naming tests poorly this documentation loses most of its usefulness. Imagine some code that has a suite of tests all named very badly as shown in listing 1-1.

public class GildedRose {
@Test
public void test1() { … }
@Test
public void test2() { … }
@Test
public void test3() { … }
}

Listing 1.1: Unnamed tests

In order for anyone to be able to tell what each of these tests is doing requires reading of each method body, which inhibits the ability to quickly identify the test required. Tests with these names do exist in the wild, but they are quite extreme. What’s more common is to see tests named for the function they are executing as can be seen in listing 1-2.

public class GildedRose {
@Test
public void updateQuality() { … }
@Test
public void updateQuality_2() { … }
@Test
public void updateQuality_AgedBrie() { … }
}

Listing 1.2: Badly named tests

These are a lot better than the previous examples but they still don’t carry all of the information required to pinpoint the behaviour being tested. In addition, code that has a variety of tests for the same method ends up acquiring meaningless labels at the end of the test name to differentiate them from previous tests. When production code fails, this will usually manifest itself as a bug report and at this point the test suite should already be passing. This means there is either an incorrect test or no test for the feature that has a bug.

In either of these cases there will be a need to quickly identify where the test is (or isn’t) and naming can be an invaluable tool. When a test itself fails, it is typically a sign that the code under test is incorrect and again, a well-named test will help identify what the feature is instead of having to read through the test code to identify what exactly is being tested. A good naming strategy should allow reading the test name as a complete sentence focussing on behaviour, as seen in listing 1-3.

public class UpdatingQuality {
@Test
public void reducesTheQualityOfAStandardItem() { … }
@Test
public void reducesTheSellInValue() { … }
@Test
public void raisesTheQualityOfAgedBrie() { … }
}

Listing 1.3: Test names focussing on behaviour

Because this example is in Java, a little imagination is needed to visualise the sentences, which become:

“Updating quality reduces the quality of a standard item”

“Updating quality reduces the sell in value”

“Updating quality raises the quality of Aged Brie”

Languages that support anonymous functions do not suffer from the restrictions of requiring the method name to carry information like they do with tools like JUnit or phpUnit, but the recommendations still hold true in these languages. One of the popular unit testing frameworks for JavaScript is Mocha, and if the above tests were written using that, they might look like something like the code shown in listing 1-4

describe('Updating Quality', function() {
it('reduces the quality of a standard item', function() { … })
it('reduces the sell in value', function() { … })
it('raises the quality of aged brie', function() { … })
})

Listing 1.4: Well-named tests using Mocha

The use of the word “should” is popular but something I personally do not like as it suggests to me that the behaviour is optional, not mandatory. The IETF RFC guidelines state that “[should], or the adjective “RECOMMENDED”, mean that there may exist valid reasons in particular circumstances to ignore a particular item, but the full implications must be understood and carefully weighed before choosing a different course.”

A lot of tutorials and documentation indicate that tests be named for the class and method they are testing. One of the biggest problems with this is that these schemes are more tied to implementation details rather than focussing on behaviour and as such are not resilient to renaming and could eventually do more harm than good if the test name is not kept up to date.

This tutorial on naming was taken from the Developer.Press ebook Tests Need Love Too by Colin Vipurs – download it now for only $3.99 on Amazon, iBooks, Google or developerpress.com.

Author
Colin Vipurs
Colin Vipurs started professional software development in 1998 and released his first production bug shortly after. He has spent his career working in a variety of industries using a wide range of technologies always attempting to release bug-free code. He holds a MSc from Liverpool University and current works at Shazam as a Developer/Evangelist. He has spoken at numerous conferences worldwide.

Comments
comments powered by Disqus