I admit publicly that I like doing code reviews. Code that is submitted for review often contains a lot of implicit information and assumptions of a fellow developer that authored it. Going into their thought process sometimes reveals what we’ll see more and more often in software development - a forgotten knowledge about some topic and a way of working that is driven by inertia. “Now wait a second Ivan,” I hear you say, “what in the world does that have to do with prefixing names of my tests with… test?”
testA, testB, testC
Not that many moons ago I had to review a piece of code written by a colleague who is around 15 years my junior. His code was usually of a solid quality and I hoped this code review would be similar to previous ones – a few comments, maybe some minor discussion about local variable type inference, approval, merge, done. But this time I noticed something. While JUnit tests were there and they worked, their names started with the word test
, followed by a “real” part of a name. I got curious about why did he do it and started digging.
“Hey man, how come all those JUnit tests in the PR are named testA, testB, testC etc?”
“Well that’s a Java standard, right?”
“Umm, not exactly. You can name your tests however you want to, as long as there is a @Test annotation on top.”
“But it’s a convention that they are prefixed with test
.”
“It was in the past. Actually back in the days we had no choice but to do that. Do you know why?”
“Honestly, no. I simply assumed it was always like that.”
“OK, let this greybeard tell you something…”
JUnit 3 has entered the chat
“JUnit was born on a flight from Zurich to the 1997 OOPSLA in Atlanta. Kent (Beck) was flying with Erich Gamma, and what else were two geeks to do on a long flight but program? The first version of JUnit was built there, pair programmed, and done test first."
— Martin Fowler
For the context, in year 1997 Java was in version 1.1, officially still called JDK 1.1. Fast-forward some 2-3 years and we saw an ascent of lightweight software methodologies such as eXtreme Programming, Crystal Clear etc. that all popularized unit testing. Naturally, Java developers turned to JUnit as their framework of choice and its then-current version JUnit 3. At the time, Java was in version 1.4, now called J2SE 1.4.
JUnit 3 had to work around a very real Java limitation. You could not mark a method as a test method, or a setup method or any other kind of method really. But JUnit needed some way to distinguish between test methods, setup methods, teardown methods, helper/private methods etc. The only tool JUnit authors had at their disposal to solve their problem was reflection. And they decided to establish a convention – method called setUp
will be executed once before each test case, methods whose names start with test
will be test cases, methods whose names start with anything else will be normal methods… If you didn’t follow the convention, some bad things would have happened, for example your test cases wouldn’t execute and you would have to figure out why!
Java 5 is here! And it has annotations!
Java 5 became available in September 2004. And it had a cool new feature - annotations. This finally enabled JUnit authors to move away from naming conventions and reflection. As a consequence, JUnit 4 (and 5) used annotations such as @Before
for setup, @Test
for test cases, @Ignore
for ignoring test case etc. So since February 2006 when JUnit 4.0 had been released there was no need to prefix test cases with test
anymore!
What happened during transition?
I don’t have hard data on this but I’ll try to make an educated guess. Large enough percentage of developers that were used to JUnit 3 way of naming methods simply continued doing the same in JUnit 4. They annotated test cases with @Test
and they continued naming them testABC
, even though the prefix wasn’t necessary any more. Newer developers simply imitated what they’ve seen from the older colleagues and didn’t bother to check where this convention comes from. As the years went passing by, a whole new generation appeared that (probably) never saw JUnit 3 but continued to name test cases as if they were still using JUnit 3. The knowledge about the real reasons about once-needed prefix is lost!
OK, how to get rid of that ugly prefix?
That depends on the state of your code base. I will offer you some pragmatic actionable advice. What I won’t do, however, is to tell you which naming convention you should use. There are dozens of articles, books and courses that discuss that issue at length.
If your code base already contains hundreds or even thousands of tests named testABC
and no or little other name patterns, it’s the best to do nothing! Code base consistency is more important than purity. You would lose a significant amount of time trying to find “better” names and to convince other team members to follow new naming convention, probably with some pushback down the road. In this case downsides outweigh upsides.
If your code base is already a mixed one, with approximately 50-50 ratio between testX
and some other naming convention, try to push for a complete conversion to that other convention. You will still have pushback from some team members, but try to convince them that testX
naming pattern is really a thing of a distant past now. Show initiative, volunteer to lead that change and perhaps even find a coworker that is willing to help you here to finish the renaming faster. While I normally never recommend it, consider doing this outside of working hours as to not step into your coworkers’ toes.
In the easiest case, you work on a code base that has only a small number of testX
test cases. You’re going to have an easy task of convincing coworkers or team lead that you should get rid of that obsolete naming convention.
Dear fellow developer, thank you for reading this article about naming JUnit tests. Until next time, TheJavaGuy saluts you!
Comments