Parameterized Tests in JUnit 5
A parameterized test allows you to run a test against a varying set of data. If you find yourself calling the same test but with different inputs, over and over again, a parameterized test would help make your code cleaner. To create one in JUnit 5 you need to:
- Annotate the test method with
@ParameterizedTest - Annotate the test method with at lease one source e.g.
@ValueSource - Consume the arguments in the test method
The sections below describe some of the commonly used source annotations you can use to provide inputs to your test methods.
@ValueSource
This annotation lets you specify a single array of literal values that will be passed to your test method one by one, as shown in the example below:
1 2 3 4 5 | @ParameterizedTest@ValueSource(ints = {2, 4, 6})void testIsEven(final int i) { assertTrue(i % 2 == 0);} |
@CsvSource
This annotation allows you to specify an array of comma-separated values, which is useful if your test method takes multiple arguments. If you have a large number of arguments, you can use an ArgumentsAccessor to extract the arguments as opposed to creating a method with a long parameter list. For example:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 | @ParameterizedTest(name = "Person with name {0} and age {1}")@CsvSource({ "Alice, 28", "Bob, 30" })void testPerson(final String name, final int age) { final Person p = new Person(name, age); assertThat(p.getName(), is(name)); assertThat(p.getAge(), is(age));}@ParameterizedTest(name = "Person with name {0} and age {1}")@CsvSource({ "Alice, 28", "Bob, 30" })void testPersonWithArgumentAccessor(final ArgumentsAccessor arguments) { final String name = arguments.getString(0); final int age = arguments.getInteger(1); final Person p = new Person(name, age); assertThat(p.getName(), is(name)); assertThat(p.getAge(), is(age));} |
By the way, note how I have also customised the display name of the test using the {0} and {1} argument placeholders.
@CsvFileSource
This annotation is similar to CsvSource but allows you to load your test inputs from a CSV file on the classpath. For example:
1 2 3 4 5 6 7 | @ParameterizedTest(name = "Person with name {0} and age {1}")@CsvFileSource(resources = { "data.csv" })void testPerson(final String name, final int age) { final Person p = new Person(name, age); assertThat(p.getName(), is(name)); assertThat(p.getAge(), is(age));} |
@MethodSource
This annotation allows you to specify a factory method which returns a stream of objects to be passed to your test method. If your test method has multiple arguments, your factory method should return a stream of Arguments instances as shown in the example below:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | import static org.junit.jupiter.params.provider.Arguments.*;@ParameterizedTest(name = "{0} is sorted to {1}")@MethodSource("dataProvider")void testSort(final int[] input, final int[] expected) { Arrays.sort(input); assertArrayEquals(expected, input);}static Stream<Arguments> dataProvider() { return Stream.of( arguments(new int[] { 1, 2, 3 }, new int[] { 1, 2, 3 }), arguments(new int[] { 3, 2, 1 }, new int[] { 1, 2, 3 }), arguments(new int[] { 5, 5, 5 }, new int[] { 5, 5, 5 }));} |
For more information, see the JUnit 5 User Guide on Parameterized Tests.
If you’re still on JUnit 4 (why?!), check out my previous post on Parameterized Tests in JUnit 4.
| Published on Java Code Geeks with permission by Fahd Shariff, partner at our JCG program. See the original article here: Parameterized Tests in JUnit 5 Opinions expressed by Java Code Geeks contributors are their own. |




