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.