Generating JUnit Test Cases Dynamically
In this post I’m going to talk about generating JUnit Test Cases Dynamically. In order to define tests, most JUnit’s users place their testing code inside test methods
that
- Start with
test
- Don’t have arguments
Given a TestCase
object, JUnit TestSuites
can dynamically extract test methods that follow these conventions and run them on the fly. However, this behavior isn’t enough in some cases. The problem of this approach is that, from the developer’s point of view, tests must be written statically.
Imagine you have a directory with many text files. For each file, you want to do the same kind of testing. Since the test result depends on each file, what you really want is to generate dynamically test cases. Of course you can have a single test method, and do all the testing there. The main problem of this approach is that Test Runners won’t be able to collect results properly: a single fail with one file would result as a failure. You won’t notice which tests are valid and which aren’t.
Generating tests cases dynamically is very simple. JUnit’s design itself is simple. This is one of the main reasons of why this framework is so successful. JUnit was created by Kent Beck and Erich Gamma. It represents an excellent oportunity to see GOF design patterns in action (in the same way that JHotDraw, another framework created by Erich Gamma as a design patterns exercise). In JUnit, a Test Case is, surprisingly, a Test Case. A Test Suite is a composite of Test Case. You can create a Test Suite as a normal object and, programmatically, populate it with as many instances of a test case as you want.
Let’s see a very simple example. Imagine you have the following structure of folders:
For each folder, you want to create a Test Suite. For each file, you want to test that its extension must be .txt
. In this way, you are going to create a parallel structure using test suites and test cases.
Below, the test suite is shown. It receives a directory in the constructor. It goes through all the contained files and subdirectories. For each subdirectory, a new TestSuite
is created and added to the composite (recursively). For each file, a new TestCase
is created and added in the same way. The actual testing is going to be done in these test case instances.
public class TextFileTestSuite extends TestSuite {
public TextFileTestSuite(File directory) {
super(directory.getName()); for (File file : directory.listFiles()) {
if (file.isDirectory()) addTest(new TextFileTestSuite(file));
else addTest(new TextFileTestCase(file));
}
}
}
The test case’s implementation is very straighforward. It receives the concrete file to test in the constructor. It also overrides the runTest()
method, where the real testing code is placed.
public TextFileTestCase(File file) {
super();
this.file = file;
setName(file.getName());
}
protected void runTest() throws Throwable {
assertTrue(file.getName().endsWith(".txt"));
}
And that’s all. You can now check the results on a Test Runner:
public class AllTests {
private static final String TEST_FOLDER = "testdata";
public static Test suite() {
TestSuite suite = new TestSuite(
"Test for net.jorgemanrubia.junitdinamically.sample");
//$JUnit-BEGIN$
suite.addTest(new TextFileTestSuite(new File(TEST_FOLDER)));
//$JUnit-END$
return suite;
}
}
With the exposed structure of folders, you will obtain something like this: