Contents

Parameterized tests with Junit

Written by: David Vlijmincx

When to use parameterized tests

Parameterized tests help you to reduce the amount of testing code you need for test cases that only need different input and or output. Instead of copying a test method multiple times, you only have to write two methods. One to test the business logic and one to supply the test with parameters.

Dependencies

You need two dependencies in your POM for parameterized tests to work. You need a recent version (5.7 or higher) of the junit engine and one for the parameterized tests self.

1
2
3
4
5
6
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.7.2</version>
    <scope>test</scope>
</dependency>

If you are already have a recent version of junit you only have to add this dependency.

1
2
3
4
5
6
<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.7.2</version>
    <scope>test</scope>
</dependency>

Example

This is the method we are going to test. It performs addition on two numbers and returns the result.

1
2
3
public int add(int firstInteger, int secondInteger) {
    return firstInteger + secondInteger;
}

Below is the method that we are going to use to supply our test method with input values. The numbers in the Argument.of(...) correspond with the parameters of the test method. When we look at Arguments.of(2, 1, 3) the 2 is firstInteger, 1 is secondInteger and 3 is expectedResult.

1
2
3
4
5
6
7
private static Stream<Arguments> valuesAndExpectedResultForAdd() {
    return Stream.of(
            Arguments.of(1, 1, 2),
            Arguments.of(2, 1, 3),
            Arguments.of(4, 2, 6)
    );
}

To make a testing method a parameterized test we need to add two annotations @ParameterizedTest and @MethodSource.

  • @ParameterizedTest tells junit the annotated method is a parameterized test method.
  • @MethodSource tells junit where to get the parameters from.
1
2
3
4
5
@ParameterizedTest
@MethodSource({"valuesAndExpectedResultForAdd"})
void add_shouldAddNumbersTogether(int firstInteger, int secondInteger, int expectedResult) {
    assertEquals(add(firstInteger, secondInteger), expectedResult);
}

Changing the names of the tests

When we run the test, we see a result similar to the one below. At first glance, it is not clear what the purpose of the test was.

1
2
3
4
add_shouldAddNumbersTogether(int, int, int)
[1] 1, 1, 2
[2] 2, 1, 3
[3] 4, 2, 6

We can make the test output a lot clearer by providing @ParameterizedTest with a name. We can set it with a String that uses {index number} to access the used parameters.

1
@ParameterizedTest(name = "adding {0} and {1} expected result: {2}")

This gives us the following output:

1
2
3
adding 1 and 1 expected result: 2
adding 2 and 1 expected result: 3
adding 4 and 2 expected result: 6

Now when a test fails, you see immediately what the input is and what the expected result is.

Conclusion

Parameterized tests help you to write more maintainable code for test cases that only differ in input or output.

Further reading

More about testing in Java: