Testing rules
Overview
Table B.6. Testing rules
TEST_001: Provide A Unit Test For Each Utility Class, Library Or Base Layer
Each utility class, library or base layer should be covered by a unit test
TEST_002: Name Test Methods Properly
Name the test method of a testcase properly. The name should not only start with "test", it should also be an accurate description of what the test does.
WRONG
public class CalcTest extends TestCase {
public void test1() {
}
public void test2() {
}
}
RIGHT
public class CalcTest extends TestCase {
public void testDivisionByZero() {
}
public void testAdditionCommutativity() {
}
}
TEST_003: Provide Mock Objects For A Unit Which Collaborates With Other Objects
Provide mock objects when the unit collaborates with other objects.
TEST_004: Only Test What Can Possibly Break
Only test what can possibly break. Do not test trivial code like most accessors and mutators (get/set methods).
TEST_005: Automate Running Unit Tests In The Build Process
Automate running unit tests in the build process.
TEST_006: Do Not Write Business Logic In Mock Objects
Don't write business logic in mock objects.
TEST_007: Run Scenario Tests As Part Of The Delivery Procedure Of A Product
Running scenario tests should be a part of the delivery procedure of the product. Preferably run the automated scenario tests at least every night. Make sure all scenario tests work before delivering production code.
TEST_008: Keep Mock Objects Independent From Each Other
Keep your mock objects independent from each other. When moch objects start to call other mock objects, this is a sign that your mock objects try to be real objects (which they shouldn't).
TEST_009: Do Not Rely On The Order Of Tests Within A Testcase
Do not assume that the tests will be performed in the order they appear in your code. When JUnit uses the Java reflection API to dynamically build the testsuite, it offers no guarantees about the order of the tests.
WRONG
public class ExampleTest extends TestCase {
public ExampleTest(String testName) {
super(testName);
}
public void testThisFirst() { }
public void testThisSecondly() {
}
}
RIGHT
Tests should be independent from each other. In the rare case that ordering tests actually makes sense (e.g. for performance reasons), use the static suite() method to order your tests :
public static Test suite() {
suite.addTest(new ExampleTest("testThisFirst"));
suite.addTest(new ExampleTest("testThisSecondly"));
return suite;
}
TEST_010: Avoid Visual Inspection In Unit Tests
Avoid visual inspection in a unit test. Instead use the assert methods to compare the results with expected values.
WRONG
public void testMessage() { System.out.println("Message body : " + message.getBody());
System.out.println("Message size : " + message.getSize());
}
RIGHT
public void testMessage() {
assertNotNull(message.getBody());
assertEquals(1000, message.getSize());
}
TEST_011: Avoid Code Duplication In Unit Tests
Avoid code duplication in unit tests. A possible solution to this is factoring out the duplicate code and maybe even moving it to a common superclass.
WORSE
public class EuroAmountTest extends TestCase {
public void testEquals() {
EuroAmount fiveEuroFiftyCents = new EuroAmount(5, 50);
EuroAmount threeEuroEightyCents = new EuroAmount(3, 80);
Assert.assertTrue(!fiveEuroFiftyCents.equals(null));
Assert.assertEquals(fiveEuroFiftyCents, fiveEuroFiftyCents);
Assert.assertEquals(threeEuroEightyCents, new EuroAmount(3, 80));
Assert.assertTrue(!fiveEuroFiftyCents.equals(threeEuroEightyCents));
}
public void testAddition() {
EuroAmount fiveEuroFiftyCents = new EuroAmount(5, 50);
EuroAmount threeEuroEightyCents = new EuroAmount(3, 80);
EuroAmount expected = new EuroAmount(9, 30);
EuroAmount result = fiveEuroFiftyCents.add(threeEuroEightyCents);
Assert.assertTrue(expected.equals(result));
}
}
BETTER
public class EuroAmountTest extends TestCase {
private EuroAmount fiveEuroFiftyCents;
private EuroAmount threeEuroEightyCents;
protected void setUp() {
fiveEuroFiftyCents = new EuroAmount(5, 50);
threeEuroEightyCents = new EuroAmount(3, 80);
}
public void testEquals() {
Assert.assertTrue(!fiveEuroFiftyCents.equals(null));
Assert.assertEquals(fiveEuroFiftyCents, fiveEuroFiftyCents);
Assert.assertEquals(threeEuroEightyCents, new EuroAmount(3, 80));
Assert.assertTrue(!fiveEuroFiftyCents.equals(threeEuroEightyCents));
}
public void testAddition() {
EuroAmount expected = new EuroAmount(9, 30);
EuroAmount result = fiveEuroFiftyCents.add(threeEuroEightyCents);
Assert.assertTrue(expected.equals(result));
}
}
TEST_012: Call setUp() and tearDown() Methods Of A Testcase's Superclass
When you subclass for your testcase
WRONG
public class ExampleTest extends AbstractExampleTest {
public void testFeatureX() {
}
public void setUp() {
}
public void tearDown() {
}
}
RIGHT
public class ExampleTest extends AbstractExampleTest {
public void testFeatureX() {
}
public void setUp() {
super.setUp();
}
public void tearDown() {
super.tearDown();
}
}
TEST_013: Isolate Test Data From Test Code
Isolate your test data from your test code. Separating test data allows you to change the test data without changing the test code.
TEST_014: Do Not Load Data From Hardcoded Locations
Do not read data from hardcode locations on the filesystem. Reading from hardcoded absolute filepaths makes the tests less portable.
Instead, put your data files on your test classpath and read the data using the static methods getResource() or getResourceAsStream() of Class. This will make the test data as portable as the test code.
TEST_015: Make Tests Locale Independent
Make sure your tests are locale independent. Running a test on a system with different locale settings should not break your tests.
TEST_016: Keep Unit Tests Small And Fast
Unit tests should be fast and small since you need to run them very often.