Parameterized unit tests with JUnit 4
By Jacob Childress on Mar 03, 2010
I'm going to share a few non-proprietary posts that I wrote for the benefit of my coworkers. I'll start with a post on JUnit. The JUnit 4 series introduced a range of features that make writing tests both easier and more expressive, but finding documentation for even simple features can be difficult.
If you've ever found yourself writing a series of tests which differ only in their inputs and expected results, you've probably realized that the sensible thing to do would be to abstract your tests into a single test that can be run against a varying set of data. JUnit 4 allows you to do this with either theories or parameterized tests; here, I'll discuss the latter.
Structure of a parameterized test class
To mark a test class as a parameterized test, you must first annotate it with
@RunWith(Parameterized.class). The class must then provide at least three entities:
- A static method that generates and returns test data,
- A single constructor that stores the test data, and
- A test.
The method that generates test data must be annotated with
@Parameters, and it must return a Collection of Arrays. Each array represents the data to be used in a particular test run. The number of elements in each array must correspond to the number of parameters in the class's constructor, because each array element will be passed to the constructor, one at a time as the class is instantiated over and over.
The constructor is simply expected to store each data set in the class's fields, where they can be accessed by the test methods. Note that only a single constructor may be provided. This means that each array provided by the data-generating method must be the same size, and you might have to pad your data sets with nulls if you don't always need a particular value.
Let's put this together. When the test runner is invoked, the data-generating method will be executed, and it will return a Collection of Arrays, where each array is a set of test data. The test runner will then instantiate the class and pass the first set of test data to the constructor. The constructor will store the data in its fields. Then each test method will be executed, and each test method will have access to that first set of test data. After each test method has executed, the object will be instantiated again, this time using the second element in the Collection of Arrays, and so on.
Parameterized test example
A sample test class with comments is below. In this class, each data set consists of a single test input and an expected result, but you can put any data that you need in there.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 @RunWith(Parameterized.class) 15 69