Unit Test Naming Conventions
There are a certain number of naming conventions used for unit tests. In the beginning, with JUnit 3, to define a test it was mandatory that the
class name was named like MyClassTest, be extending from TestCase and
all the test method names were starting with 'test' as in
'testMyMethod()'. I think that this is a good example of convention over
configuration.
With JUnit 4 (or TestNG) this is longer mandatory and it leaves the
developer free to define his own naming convention. But then you
"configure" the method as a test using the @Test annotation.
There is a naming convention defined by BDD which says that the test class and the test methods should describe the behavior you want to verify.
Examples:
having the test methods starting with should
public class WhenWindowControlCloseWindow {
@Test
public void shouldCloseWindows() {
//...
}
}
Or as in this example (from wikipedia), which also uses comments to describe the test: given/when/then:
public class WindowControlBehavior {
@Test
public void shouldCloseWindows() {
// Given
WindowControl control = new WindowControl("My AFrame");
AFrame frame = new AFrame();
// When
control.closeWindow();
// Then
ensureThat(!frame.isShowing());
}
}
or another convention I saw:
public class WindowControlShould {
@Test
public void closeWindows() {
//...
}
}
The problem here is that you have 3 elements in a test: the 'entity'
subject of the test (usually a class name), the condition ('when calling
some method with some specific parameters), and the expected result,
that as we saw in BDD with the "shouldDoSomething" method name.
So the problem is that with the class name and the method name we only
have two elements to describe our test.
To express the 3rd 'entity' of the phrase, I tried to use inner classes to define tests like this:
public class WindowControl
public static class WhenCloseWindow {
@Test
public void shouldCloseWindows() {
//...
}
}
}
But it isn't supported by JUnit4.
I thought that packages might help, like specifying them as
package com.mycompany.blah.blah.windowcontrol;
public static class WhenCloseWindow {
@Test
public void shouldCloseWindows() {
//...
}
}
But in this way you lose the possibility to invoke default and package accessible methods, which is a thing that I quite like in my tests.
My feeling now is that first the test methods were identified by a
naming convention. Then with the annotation, the convention has been
left to the developer to choose, or even the choice to not have a
convention at all. The annotation, for me is more close to a
configuration thing, which is replacing a convention; a sort of
counter-tendency in the trend of convention over configuration paradigm.
So if we start to call our test method shouldSomething() are we not going back to the old convention testSomething() ?
Well I liked the conventions used in JUnit 3 and I don't really see big
improvements in using the annotations, or being free from extending the
TestCase class, which was providing the assert* methods: with JUnit4 we have to static import those methods from the class Assert; I don't see it as an improvement.
My taste is that, if we can't easily find a descriptive naming
convention for what we are testing, relying on some comments could be
the best thing. The example above - the one coming from wikipedia - is
in fact using a naming convention plus some comments in the
code. I think that using a comment on top of the method would have
served better the purpose of describing the test.
Finally, some continuous integration tools are able to format the
test names (class + method) to show a sentence describing the test
nicely in natural English language.
That is cool, but since we have the @Test annotation already there to
configure the test, why not having a descriptive attribute that can be
used from reporting tools, like:
@Test(description="when WindowController.closeWindow() is invoked the window is closed")
public void testCloseWindow() {
//...
}
Or, since I criticized the @Test annotation, a short java comment would have sorted the same purpose for the tools willing to describe the test with a plain English description.
Since there isn't around a really good naming convention for tests, since I don't see real improvements using annotations and static imports... I think that JUnit 3 was doing right.
What do you think?
From http://en.newinstance.it/2011/01/28/unit-test-naming-conventions/
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)






Comments
Andrei Solntsev replied on Wed, 2011/02/02 - 12:44pm
Hi,
good topic. I have been thinking of that syntax for a while, and it seems that the best option is using JVM-compatible languages for writing unit-tests. For example, ScalaTest:
http://www.scalatest.org/getting_started_with_bdd
Andrei Solntsev replied on Thu, 2011/02/03 - 11:07am
Hi,
actually it's possible to use inner classes with JUni 4. Look for examples:
http://kentbeck.github.com/junit/javadoc/latest/org/junit/experimental/runners/Enclosed.html
Luigi Viggiano replied on Thu, 2011/02/03 - 4:40pm
Luigi Viggiano replied on Fri, 2011/02/04 - 6:50am
Thanks to Andrei (for the above comment) I found my unit test naming convention.
I am writing a maintenance feature which removes some old feed files from a directory, here is a sample of how I am doing it:
Raveman Ravemanus replied on Fri, 2011/02/04 - 11:29am
I like the @Test testWhatItDoes rule, because its backward compatible.
I don't understand why you are using BDD's should. If you really want to use BDD there are BDD frameworks and one, extra spam word before every method is not helping anyone.
Esko Luontola replied on Fri, 2011/02/04 - 4:50pm
Personally, I write test names as full English sentences which describe features. I used to write all my tests with 2-level nesting (similar to org.junit.experimental.runners.Enclosed, but with the JDave framework or my own JUnit runner similar to Enclosed), but since then I've created testing frameworks [1] where I'm free to use whatever nesting level, even within the same test class. So nowadays I tend to mix both 1-level and 2-level nesting. First I write it as a 1-level test, but then if I notice that it is testing more than on feature, then I will split it into 2-level tests with a common setup.
[1] GoSpec for Go, and Specsy for Scala - later I'll port it for other JVM languages.
Sławomir Czerwiński replied on Thu, 2011/03/03 - 4:11am
Hi,
For all interested, this construction is valid for TestNG as well:
import org.testng.annotations.Test; public class WindowControl public static class WhenCloseWindow { @Test public void shouldCloseWindows() { //... } } }If You include classes (not packages) in Your test, You should include
WindowControl$WhenCloseWindowexplicitly. ClassWindowControlitself is not required then.