JUnit Utilities is a toolkit with a few utility classes that can help building JUnit test case/test suite more flexibly than directly supported by JUnit API.
TestSuiteBuilder
It is a well-known idiom to have an AllTests class that covers all the test cases of aproject or a package. However, manually registering test cases in AllTests is tedious. TestSuiteBuilder can make the job easier.
Instead of registering your test case classes individually as in:
public class AllTests extends TestCase { public static TestSuite suite(){ TestSuite suite = new TestSuite(); suite.addTestSuite(TestCase1.class); suite.addTestSuite(TestCase2.class); suite.addTestSuite(TestCase3.class); ... } }
You can simply use a one-liner:
public class AllTests extends TestCase { public static TestSuite suite(){ return TestSuiteBuilder.suite(AllTests.class); } }
And all test cases under the same package and sub-packages are automatically detected and registered in the test suite.
assertArrayEquals
JUnit 3.8.x doesn't provide assertion for array equality. In case your project cannot use JUnit 4.x at the moment (it requires Java 5), JUnitUtils.assertArrayEquals can be used to help the situation.
This assert gives more detailed failure message (length difference? the 2nd element is not equal?) than assertTrue(Arrays.equals(arr1, arr2)).
For example:
assertEquals(new Object[]{"a","b"}, someApiThatReturnsAnArray());
buildTestSuiteFromNestedClasses
Ocasionnally, it makes sense to keep a few closely related test case classes as nested classes and provide a suite() method in the enclosing class to create a TestSuite containing all the nested test cases.
For example:
public class EnrollmentHandlerTestSuite extends TestCase { public static TestSuite suite(){ TestSuite suite = new TestSuite(); suite.addTestSuite(NotificationServiceEnabledTest.class); suite.addTestSuite(NotificationServiceDisabledTest.class); } public static class NotificationServiceEnabledTest extends EnrollmentHandlerTest{ public NotificationServiceEnabledTest(){ super(true); } } public static class NotificationServiceDisabledTest extends EnrollmentHandlerTest{ public NotificationServiceDisabledTest(){ super(false); } } }
In this example, we want to use the same test methods defined in EnrollmentHandlerTest class, yet each test method should be run with both "notification service enabled" and "notification service disabled".
It is not a problem in this case as only two nested classes are needed to populate the TestSuite. It may become a pain if more nested classes are created. For this purpose, the JUnitUtils.buildTestSuiteFromNestedClasses can help. Using this helper method, the suite() method will become:
public static TestSuite suite(){ return JUnitUtils.buildTestSuiteFromNestedClasses( EnrollmentHandlerTestSuite.class); }
where all nested test classes are automatically populated as a TestSuite.
buildTestSuiteFromInnerClass
In the above example, a few subclasses are created to reuse the same super test class using different options or testing strategies. It may become unwieldy if the number of options or strategies scales up.
For example, we may have an array of 20 different strategies that we want to use the same test class to test. It will cause class explosion if we create 20 subclasses each representing one strategy. Worse, if we ever need to save the options externally in a properties file or something, the creating-subclass-statically approach simply will not work for problem of such dynamic nature.
Such problem is called "parameterized test", and is supported in JUnit 4.x with the @Parameters and @RunWith annotations.
In 3.8.x, however, one can use JUnitUtils.buildTestSuiteFromInnerClass() to help. What you do is to declare the actual test class as inner class, which has access to the strategy data stored in the outer class:
public class TestClassWithStrategy extends TestCase { private final SomeTestStrategy strategy; TestClassWithStrategy(SomeTestStrategy strategy){ this.strategy = strategy; } public static TestSuite suite(){ SomeTestStrategy[] strategies = ...; TestSuite suite = new TestSuite("all strategies"); for(int i=0; i<strategies; i++){ TestSuite innerSuite = JUnitUtils.buildTestSuiteFromInnerClass(new TestClassWithStrategy(strategies[i]), ActualTests.class); suite.addTest(innerSuite); } return suite; } public class ActualTests extends TestCase { public void test1(){ //can use strategy variable here } public void test2(){ //can use strategy variable here } } }
As the enclosing instance will be used by many test instances of the inner class, be sure to make it stateless (preferrably immutable) to not break test isolation.
