The naming schema of test classes and test methods can make a real difference. If consistent and well thought out, it will help you go to the right place in your code - exactly where you want to be. If chaotic, with no obvious patterns, it will slow down your development by forcing you to browse through your codebase class by class instead of jumping instantly to this one important place. Another important thing about naming is that it helps us to understand the role and purpose of each test. This is very important when adding new tests or when looking to identify the reason for a particular test failure.
In this section we will take a look at two main factors which impact on how hassle-free or problematic your experience of working with test code is likely to be: names of test classes and names of test methods.
Additionally we will also consider naming schemas for test-doubles.
9.2.1. Test Class Names
The most popular pattern for naming test classes is to append a Test suffix to the name of the class being tested. This results in test classes like UserDAOTest, PasswordValidatorTest and BankAccountTest, which test production classes named UserDAO, PasswordValidator and BankAccount respectively. The benefits of this pattern are the following:
Chapter 9. Organization Of Tests
• allow you to move quickly between test and production code with your IDE (so, for example, you can jump from BankAccount to BankAccountTest with one keyboard shortcut),
• there is a one-to-one mapping between production class and test class, so you know that:
• all tests of the given class are in this one place,
• and, vice-versa, that this test class contains nothing but tests for a single class,
• it is commonly used (so everyone feels at home when your code follows this schema).
There are not many counterproposals for test class naming schemes1. The overwhelming majority of code that I have seen follows the simple schema presented above. And there are not many reasons, if any, for you not to follow it as well. I follow this pattern 99% of the time (and would encourage you to do the same), but there are also some cases where I renounce it. Two of them are described below.
Splitting Up Long Test Classes
When a test class starts to grow beyond the "safety limit" I have established for myself, I start to wonder whether splitting it up would not perhaps be a good idea. A common scenario, when I do split a test class up, is that there is a lot of arguments checking and numerous tests for expected exceptions. I usually move these tests to a separate class and use a different suffix - WrongValuesTest - to distinguish it. In the case of an exemplary MyClass, I would end up with the following test classes:
1. MyClassTest - all tests that puts the "valid" behaviour of the class through its paces. This test class shows the right way to use MyClass.
2. MyClassWrongValuesTest - all tests that put the SUT through its paces and fail (fast!) with an expected exception. This test class shows what happens when MyClass is used in an incorrect way.
The second test class - MyClassWrongValuesTest - is usually much simpler (but sometimes longer) than
MyClassTest. Often it will contain some data providers, whose role is to provide various illegal values for different test methods. Test doubles are rarely required there (except, maybe, for dummies); this is because no methods are really called on them, as arguments checking is usually the first thing you do.
The necessity of splitting up a test class might by indicative that what you should really be splitting up is the class being tested itself! If it cannot be tested with one test class, maybe it is too big - maybe it has too much responsibility? If so, then fix this problem, and the test class will automatically shrink to an appropriate length.
Test Class Per Feature
Another way to go with test class naming is to base their name not only on a tested class, but also on a tested feature. The following story illustrates the usability of such an approach.
One day I was asked to introduce a change to a certain legacy code class called DataProvider. This class was responsible for some computations and offered some methods which returned the mean values of some calculated numbers. The then current implementation was to return null if some data required
1One that I am aware of, derived from the BDD approach, makes the test class name part of a "when" element of a BDD convention - see http://www.slideshare.net/wakaleo/junit-kung-fu-getting-more-out-of-your-unit-tests
Chapter 9. Organization Of Tests
for calculations was missing. At some point our client introduced a new monitoring tool, which was consuming data returned by the DataProvider class in order to draw some charts. It transpired that this new tool did not like null values at all, so a change was requested – so that it would return zeros instead of null values.
I took a look at the existing code, and found no tests for the class. It was not possible to test the class thoroughly (because it would have taken too much time), so I decided to only introduce tests which would cover the functionality in question. Because I did not intend to test the whole class, I decided to abandon the ClassNameTest pattern. Instead, I created a new test class and called it DataProviderMeanValuesZerosInsteadOfNullsTest. Even though it went against the norms of my working practice, I felt it was the right thing to do. The test class name indicated clearly that it was meant to test the DataProvider class, the suffix informed people that it was a test class, and the rest served to indicate what part of the class functionality was being tested.
If it ever should come about that we decide to cover the whole class with tests (not very likely, though…), then the DataProviderMeanValuesZerosInsteadOfNullsTest will probably be merged into it.
9.2.2. Test Method Names
JUnit, like all current testing frameworks, give you complete freedom when it comes to naming test methods. This is because identification of test methods is based on annotations and not on method names.
With freedom, though, comes a need to make choices, and many different options to choose from. Let’s discuss this issue and see if we can get to choose the best one.
Please refer to Section 10.1 for additional discussion about why some naming schemas are more appropriate than others.
Historically, method names were prefixed with the word test - e.g. testConstructor(),
testReturnsNonNullArray(), etc. This naming schema was popularized (or rather enforced) by older versions of JUnit, which treated all methods that followed this pattern as test methods and executed them during tests execution (ignoring any methods with different names). And for a long time everyone was happy with it.
However, the limitations of this naming schema started to show up. First of all, it was not obvious what a particular test method was all about, just by looking at its name. It was quite common to find lengthy test methods which, under a common name such as, for example, testUserAdd(), verified many features of a class being tested. This was especially painful when dealing with failed tests, as there was not much one could learn from the information that "testUserAdd() has failed". Such an error message does not inform us about exactly what has failed: i.e. which feature of the class tested is not working properly. Because of this, method names started to grow and contain much more information.
For example testConstructor() was split into several more focused test methods with names like
testConstructorThrowsExceptionForInvalidArguments(), for example.
Chapter 9. Organization Of Tests
this meant they were really irritated by the presence of this obligatory test prefix. Many of us demanded that failed test messages should be readable as proper English sentences (or, at least, be as close to this ideal as possible). The rescue came with a new wave of testing frameworks (TestNG in particular) which used annotations instead of method names patterns to recognize test methods. This made it possible to come up with a more readable naming pattern.
This new pattern was based on the idea that the test method name should convey information about the following:
• preconditions of the test - the state of the SUT and the environment before the test,
• triggering actions - what makes the SUT act in the expected way,
• expected results of the test - what should be returned by the SUT, or what state the SUT should be in after the test is finished, or what actions should be performed by the SUT during the test,
• optionally, the name or role of the SUT,
• in addition, the test prefix was replaced with should, which allows one to create specification-like method names.
Of course, it is usually not possible to include a full description of all these kinds of information in the method name itself. What is possible, though, is to include just enough details to convey the main purpose of the test. Also, each of the elements can be omitted, if its presence does not enhance the readability of the test method. Table 9.1 provides some examples of test method names which follow the guidelines described above.
Table 9.1. Examples of test method names
class name test methods
constructorShouldThrowExceptionForNullUser() OrderTest
constructorShouldCreateValidOrderForValidUser() shouldNotAcceptDictionaryBasedPasswords() shouldNotAcceptPasswordWithoutDigits() shouldNotAcceptShortPasswords()
PasswordValidatorTest
shouldAcceptLongComplicatedPassword() shouldAllowToBookTableForOneHourAndMore() shouldDisallowToBookForLessThanHour() shouldAllowToCreateRecurrentReservation() BookingSystem
shouldAllowToCancelExistingReservation()
In the case of the examples presented in Table 9.1, all test method names specify exactly what is expected of the SUT (e.g. shouldThrow…(), shouldNotAccept…(), shouldAllow…()), and under what conditions or with what arguments (e.g. …ForNullUser(), …PasswordsWithoutDigits(), …ExistingReservation()).
When a test fails, the first line of the message already furnishes us with enough information to understand what it is that is not working properly.
Chapter 9. Organization Of Tests
What is attractive about this naming schema is that it leaves some room for customization. Some of the examples shown in Table 9.1 do not start with should, but with the constructor prefix, which makes it clearer which part of the SUT is being tested by a particular method.
Test method names are of secondary importance compared to their content, but they can push your thinking in the right direction - or, for that matter, the wrong one. The use of the
"should" prefix helps (some people would say forces) us to focus on the expected behaviour of the SUT, and leads to "testing behaviour and not methods" (see Section 10.1). Thinking in terms of the responsibilities of the SUT will make you test at the right level of abstraction.
This is especially important when coding code-first, because it is then so very easy to test implementation details instead of the behaviour of an external SUT.
9.2.3. Naming of Test-Double Variables
Let us take a look at the variable names we have used so far when working with test doubles. An example is given in the listing below.
Listing 9.2. Original variables' names
Messenger messenger;
TemplateEngine templateEngine;
MailServer mailServer;
The names of variables, as shown in Listing 9.2, inform us about the types of objects (e.g. it is obvious that mailServer is of the MailServer type). However, they do not convey any information concerning the role which these objects play in our tests. One of them is an SUT, another one a test spy, another a stub. Yet this difference is not expressed by the names of the variables in test code, and can only be discovered on closer inspection.
Some people suggest giving more intention-revealing names to all variables. For example:
Listing 9.3. Intention-revealing names of variables
Messenger sut;
TemplateEngine stubTemplateEngine;
MailServer spyMailServer;
This version of the names of the variables gives much more insight into their purpose in test class. A single glance is sufficient to let us know that the real testing is to be done using sut and spyMailServer, while stubTemplateEngineReq is only assisting in this process.
Another variation of this idea is to reverse the order and put the type of test double as a suffix, e.g.
mailServerSpy, templateEngineStub. This way the information concerning the type of the object is more easily visible – something which some people consider more valuable.
It is up to you to decide whether you find this worthwile. With short tests, with a very limited number of DOCs (as they should be), these additional hints, embedded within the variable names, are rather unnecessary. If you have more DOCs and more complex tests than it may help you to understand the tests. On the other hand, short, simple, focused tests are what we should be striving for, so instead of
Chapter 9. Organization Of Tests