Parameterized Tests With JUnit
Learn how to speed up test execution by using parameterized tests with JUnit, as shown in this tutorial.
Join the DZone community and get the full member experience.
Join For FreeWhat Is Parameterized Testing in JUnit?
JUnit allows you to use parameters in a tests class. This class can contain multipletest methods and each method is executed with the different parameters provided. It helps developers save time when executing the same tests which differ only in their inputs and expected results.
There are five steps that you need to follow to create a parameterized test.
- Annotate the test class with
@RunWith(Parameterized.class)
- Define test data: create a public static method, annotated with
@Parameters
, that returns a Collection of Objects (as Array) as the test data set. - Define instance variable for each "column" of test data.
- Use test data in test: you can use the
@Parameter
annotation in public fields to get the test values injected in the test or create a public constructor that takes in what is equivalent to one "row" of test data. - Create your test case(s) using the instance variables as the source of the test data.
Note: Every JUnit test (annotated with @Test
) is executed with each row of the test data set. If you have four tests and twelve data rows, this will result in forty-eight tests.
A code example has been created below based on these steps.
Annotate the Test Class
The class needs to be run with a specialized runner in order to be treated as a parameterized test. The runner is org.junit.runners.Parameterized. The class looks like this:
import org.junit.Test;
import org.junit.runners.Parameterized;
import org.junit.runner.RunWith;
@RunWith(Parameterized.class)
public class ParameterizedTestUsingFields {
}
Define the Test Data
Test data is seeded from the static method public static Collection<Object> data()
; this method is annotated with @Parameterized.Parameters
. The annotation may accept the "name"argument, which can display data from each row by its index: name ="{index}:Test with m1={0}, m2={1}, result is:{2}", where {index} is the current test in the data set sequence and {0},{1}, and {2} are the first, second, and third elements from the Object array. Here is how the test data is defined:
// creates the test data
@Parameterized.Parameters(name = "{index}: Test with m1={0}, m2 ={1}, result is:{2} ")
public static Collection<Object[]> data() {
Object[][] data = new Object[][]{{1, 2, 2}, {5, 3, 15}, {121, 4, 484}};
return Arrays.asList(data);
}
As shown in the above code snippet, the data is a 3*3 array where each row is a single input for the test.
Define the Instance Variable and Use the Test Data in a Test
Class instance variable fields are needed to store every index from the Object array representing test data rows. There are two ways to store each "row" of data into instance variable fields by using either the constructor or place annotation @Parameter
above each instance variable field. The number of elements in each array provided by the method annotated with @Parameter
must correspond to the number of parameters in the constructor of the class.
If using @Parameter
, the instance variable field must be public. Otherwise, an error will occur.
Using @Parameter
// fields used together with @Parameter must be public
@Parameterized.Parameter(0)
public int m1;
@Parameterized.Parameter(1)
public int m2;
@Parameterized.Parameter(2)
public int result;
Using Constructor
// fields used can be private, no need to be public
private int m1;
private int m2;
private int result;
public ParameterizedTestUsingFields(int m1, int m2, int result) {
this.m1 = m1;
this.m2 = m2;
this.result = result;
}
Create Your Test Case***
The following code shows an example of a parameterized test. It tests the multiply()
method of the ToTestClass
class, which is included as the inner class for the purpose of this example.
@Test
public void testMultiplyException() {
ToTestClass tester = new ToTestClass();
assertEquals("Result", result, tester.multiply(m1, m2));
}
// class to be tested
class ToTestClass {
public int multiply(int i, int j) {
return i * j;
}
}
Putting It All Together
Combining all these steps into one class leads to a unit test, as shown below. You can get the source code on GitHub.
package com.tutorial.junit.parameterizedTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import java.util.Arrays;
import java.util.Collection;
import static org.junit.Assert.assertEquals;
@RunWith(Parameterized.class)
public class ParameterizedTestUsingFields {
// fields used together with @Parameter must be public
@Parameterized.Parameter(0)
public int m1;
@Parameterized.Parameter(1)
public int m2;
@Parameterized.Parameter(2)
public int result;
// creates the test data
@Parameterized.Parameters(name = "{index}: Test with m1={0}, m2 ={1}, result is:{2} ")
public static Collection<Object[]> data() {
Object[][] data = new Object[][]{{1, 2, 2}, {5, 3, 15}, {121, 4, 484}};
return Arrays.asList(data);
}
@Test
public void MultiplyTest() {
ToTestClass tester = new ToTestClass();
assertEquals("Result", result, tester.multiply(m1, m2));
}
// class to be tested
private class ToTestClass {
public int multiply(int i, int j) {
return i * j;
}
}
}
Opinions expressed by DZone contributors are their own.
Comments