Limiting asserts in test cases
During the boogie of development with tight schedules and impending Disco Dances, it’s tempting to try and fit everything into a test case. This haphazardness tends to lead to an abundance of assert methods ending up in one test case.
For example, the code below attempts to verify the behavior of HierarchyBuilder’s buildHierarchy method as well as the behavior of the Hierarchy object in one test case.
public void testBuildHierarchy() throws Exception{
Hierarchy hier = HierarchyBuilder.buildHierarchy(
"test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
assertEquals("should be 2", 2,
hier.getHierarchyClassNames().length);
assertEquals("should be junit.framework.TestCase",
"junit.framework.TestCase",
hier.getHierarchyClassNames()[0]);
assertEquals("should be junit.framework.Assert",
"junit.framework.Assert",
hier.getHierarchyClassNames()[1]);
}
Note how there are three assert methods, man. This is a valid JUnit test case; there is nothing prohibiting the inclusion of multiple asserts in a test case.
The problem, however, with this practice is that JUnit is built to be fast failing. If the first assert fails, the whole test case is abandoned from the point of failure. This means that the next two tripping asserts are not run during that test run.
Once a code fix is completed and the test is rerun, the second assert may fail, which causes the whole fix-rerun test case cycle to repeat. If when running the second try, the third assert fails, yet again, the process repeats. Notice an inefficient, uptight pattern here?
A more effective practice is to try and limit one assert to each test case. This way, rather than repeating a three step process as you would in the example above, there would be three failures in one test run.
For example, the code from above would be refactored into three separate test cases (and a fixture).
private Hierarchy hier;
protected void setUp() throws Exception {
hier = HierarchyBuilder.buildHierarchy(
"test.com.vanward.adana.hierarchy.HierarchyBuilderTest");
}
public final void testBuildHierarchyStrSize() throws Exception{
TestCase.assertEquals("should be 2", 2,
hier.getHierarchyClassNames().length);
}
public final void testBuildHierarchyStrNameAgain() throws Exception{
TestCase.assertEquals("should be junit.framework.TestCase",
"junit.framework.TestCase",
hier.getHierarchyClassNames()[0]);
}
public final void testBuildHierarchyStrName() throws Exception{
TestCase.assertEquals("should be junit.framework.Assert",
"junit.framework.Assert",
hier.getHierarchyClassNames()[1]);
}
With three separate test cases, in the first test run, three failures are reported. This way, you can limit yourself to one fix-rerun cycle. This practice, of course, leads to a proliferation of test cases; however, there is a benefit to that: the number of test cases grows at a smokin’ pace!
| Related odds and ends | ||
|---|---|---|
Wednesday 15 Feb 2006 | Developer Testing, JUnit
So true about the number of test cases growing. I’m working on a Rails app now and writing the functional tests; seeing that line of dots get a little bit longer after adding each test is a beautiful thing.