JUnit best practices
Techniques for building resilient, relocatable, multithreaded JUnit tests
By and Andy Schneider, JavaWorld.com, 12/21/00
Page 2 of 5
Don't assume the order in which tests within a test case run
You should not assume that tests will be called in any particular order. Consider the following code segment:
public class SomeTestCase extends TestCase {
public SomeTestCase (String testName) {
super (testName);
}
public void testDoThisFirst () {
...
}
public void testDoThisSecond () {
}
}
In this example, it is not certain that JUnit will run these tests in any specific order when using reflection. Running the tests on different platforms and Java VMs may therefore yield different results, unless your tests are designed to run in any order. Avoiding temporal coupling will make the test case more robust, since changes in the order will not affect other tests. If the tests are coupled, the errors that result from a minor update may prove difficult to find.
In situations where ordering tests makes sense -- when it is more efficient for tests to operate on some shared data that establish a fresh state as each test runs -- use a staticsuite()
method like this one to ensure the ordering:
public static Test suite() {
suite.addTest(new SomeTestCase ("testDoThisFirst";));
suite.addTest(new SomeTestCase ("testDoThisSecond";));
return suite;
}
There is no guarantee in the JUnit API documentation as to the order your tests will be called in, because JUnit employs aVector
to store tests. However, you can expect the above tests to be executed in the order they were added to the test suite.
Avoid writing test cases with side effects
Test cases that have side effects exhibit two problems:
- They can affect data that other test cases rely upon
- You cannot repeat tests without manual intervention
In the first situation, the individual test case may operate correctly. However, if incorporated into aTestSuite
that runs every test case on the system, it may cause other test cases to fail. That failure mode can be difficult to diagnose, and the error may be located far from the test failure.
In the second situation, a test case may have updated some system state so that it cannot run again without manual intervention, which may consist of deleting test data from the database (for example). Think carefully before introducing manual intervention. First, the manual intervention will need to be documented. Second, the tests could no longer be run in an unattended mode, removing your ability to run tests overnight or as part of some automated periodic test run.
Call a superclass's setUp() and tearDown() methods when subclassing
When you consider:
public class SomeTestCase extends AnotherTestCase {
// A connection to a database
private Database theDatabase;
public SomeTestCase (String testName) {
super (testName);
}
public void testFeatureX () {
...
}
public void setUp () {
// Clear out the database
theDatabase.clear ();
}
}
Can you spot the deliberate mistake?setUp()
should callsuper.setUp()
to ensure that the environment defined inAnotherTestCase
initializes. Of course, there are exceptions: if you design the base class to work with arbitrary test data, there won't be a problem. (Continued)