loading...

December 29, 2018

JUnit 5: Using Lists as an Argument for Parameterized Tests

JUnit 5 is one of the most common Java frameworks for unit tests. Version 5 offers parameterized test and is the new major release that replaces the older version 4 which was already released 2006.

Parameterized tests could be enabled with the annotation @ParameterizedTest. They could be provided with data and could also be run several times with different values. In addition to providing parameterized tests with primitive data via the annotation @ValueSource, it is also possible to pass more complex data via the annotation @MethodSource. This article will show how to provide several lists for a parameterized test in JUnit 5.

Method as a Source for Arguments

To provide a parameterized test with arguments, the annotation @MethodSource could be used. In parentheses, the name of the method supplying the arguments is written down.

@ParameterizedTest
@MethodSource("methodForArguments")
public void paramTest(int a, int result) {
    assertEquals(result, Math.pow(a, 2));
}

Arguments as Streams

The method supplying the arguments has to return a stream of arguments: Stream<Arguments>. You could use Arguments.of(Object... args) to wrap any desired numbers of values in an instance of the interface Arguments. The values wrapped in this interface should match both the number and the type of the requested arguments of the test method. To create a stream out of several instances of this interface, use the method Stream.of(Arguments... args).

private static Stream<Arguments> methodForArguments() {
    return Stream.of(
            Arguments.of(2, 4),
            Arguments.of(3, 9),
            Arguments.of(4, 16)
    );
}

Streams of a Single Argument

However, if only a single argument is needed, the source method does not have to wrap each argument in an instance of Arguments.

private static Stream<Integer> singleArguments() {
    return Stream.of(1, 2, 3);
}

@ParameterizedTest
@MethodSource("singleArguments")
public void paramTest2(int number) { }

Stream of a List

Instead of using the method Stream.of(Arguments... args), lists in Java could be used to create a stream.

private static Stream<Integer> singleArguments() {
    List list = List.of(1, 2, 3);
    return list.stream();
}

This list could either provide single values as arguments or it could be a list with multiple instances of the interface Arguments.

private static Stream<Arguments> methodForArguments() {
    List listWithArguments = List.of(
            Arguments.of(2, 4),
            Arguments.of(3, 9),
            Arguments.of(4, 16)
    );
    return listWithArguments.stream();
}

The values for creating an instance of Arguments could be, of course, of any type. Like this, it is also possible using data types like List.

Use Case: List as an Argument Type

In this use case, the test needs a List, int and long. The test should be run multiple times with different lists and numbers.

@ParameterizedTest
@MethodSource("generateArgumentsStream")
public void exampleTest(List<Integer> list, int intVal, long longVal) { }

To create a list, I wrote a method which requests a length, a minimum and a maximum value. Arguments of length=6, min=1 and max=3 creates the list 1, 2, 3, 1, 2, 3.

The demanded stream is created by converting a List of Arguments into a stream. Arguments.of(Object... args) is used to wrap a List, an int and a long. Next, it is added to a list; a List of Arguments gets created. Finally, the new list is transformed into a stream.

private static Stream<Arguments> generateArgumentsStream() {
    List<Arguments> listOfArguments = new LinkedList<>();
    listOfArguments.add(Arguments.of(generateTestList(100, min, max), intVal, longVal));
    listOfArguments.add(Arguments.of(generateTestList(200, min, max), intVal, longVal));
    listOfArguments.add(Arguments.of(generateTestList(300, min, max), intVal, longVal));
    return listOfArguments.stream();
}

@ParameterizedTest
@MethodSource("generateArgumentsStream")
public void exampleTest(List<Integer> list, int intVal, long longVal) { }

To see the full example with more details, see the tests on my GitHub page.

Posted in JavaTaggs: