Dependencies
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
@ParameterizedTest
@ValueSource
@ParameterizedTest @ValueSource(ints = {1, 3, 5, -3, 15, Integer.MAX_VALUE}) // six numbers void isOdd_ShouldReturnTrueForOddNumbers(int number) { assertTrue(Numbers.isOdd(number)); }
@NullSource @EmptySource @NullAndEmptySource
As of JUnit 5.4, we can pass a single null value to a parameterized test method using @NullSource:
@ParameterizedTest @NullSource void isBlank_ShouldReturnTrueForNullInputs(String input) { assertTrue(Strings.isBlank(input)); }Since primitive data types can’t accept null values, we can’t use the @NullSource for primitive arguments.
Quite similarly, we can pass empty values using the @EmptySource annotation:
@ParameterizedTest @EmptySource void isBlank_ShouldReturnTrueForEmptyStrings(String input) { assertTrue(Strings.isBlank(input)); }@EmptySource passes a single empty argument to the annotated method.
For String arguments, the passed value would be as simple as an empty String. Moreover, this parameter source can provide empty values for Collection types and arrays.
In order to pass both null and empty values, we can use the composed @NullAndEmptySource annotation:
@ParameterizedTest @NullAndEmptySource void isBlank_ShouldReturnTrueForNullAndEmptyStrings(String input) { assertTrue(Strings.isBlank(input)); }As with the @EmptySource, the composed annotation works for Strings, Collections, and arrays.
To pass a few more empty string variations to the parameterized test, we can combine @ValueSource, @NullSource, and @EmptySource together:
@ParameterizedTest @NullAndEmptySource @ValueSource(strings = {" ", "\t", "\n"}) void isBlank_ShouldReturnTrueForAllTypesOfBlankStrings(String input) { assertTrue(Strings.isBlank(input)); }
@EnumSource
In order to run a test with different values from an enumeration, we can use the @EnumSource annotation.
For example, we can assert that all month numbers are between 1 and 12:
@ParameterizedTest @EnumSource(Month.class) // passing all 12 months void getValueForAMonth_IsAlwaysBetweenOneAndTwelve(Month month) { int monthNumber = month.getValue(); assertTrue(monthNumber >= 1 && monthNumber <= 12); }Or, we can filter out a few months by using the names attribute.
We could also assert the fact that April, September, June and November are 30 days long:
@ParameterizedTest @EnumSource(value = Month.class, names = {"APRIL", "JUNE", "SEPTEMBER", "NOVEMBER"}) void someMonths_Are30DaysLong(Month month) { final boolean isALeapYear = false; assertEquals(30, month.length(isALeapYear)); }By default, the names will only keep the matched enum values.
We can turn this around by setting the mode attribute to EXCLUDE:
@ParameterizedTest @EnumSource( value = Month.class, names = {"APRIL", "JUNE", "SEPTEMBER", "NOVEMBER", "FEBRUARY"}, mode = EnumSource.Mode.EXCLUDE) void exceptFourMonths_OthersAre31DaysLong(Month month) { final boolean isALeapYear = false; assertEquals(31, month.length(isALeapYear)); }In addition to literal strings, we can pass a regular expression to the names attribute:
@ParameterizedTest @EnumSource(value = Month.class, names = ".+BER", mode = EnumSource.Mode.MATCH_ANY) void fourMonths_AreEndingWithBer(Month month) { EnumSet<Month> months = EnumSet.of(Month.SEPTEMBER, Month.OCTOBER, Month.NOVEMBER, Month.DECEMBER); assertTrue(months.contains(month)); }Quite similar to @ValueSource, @EnumSource is only applicable when we’re going to pass just one argument per test execution.
@CsvSource
@ParameterizedTest @CsvSource({"test,TEST", "tEst,TEST", "Java,JAVA"}) void toUpperCase_ShouldGenerateTheExpectedUppercaseValue(String input, String expected) { String actualValue = input.toUpperCase(); assertEquals(expected, actualValue); }@ParameterizedTest @CsvSource(value = {"test:test", "tEst:test", "Java:java"}, delimiter = ':') void toLowerCase_ShouldGenerateTheExpectedLowercaseValue(String input, String expected) { String actualValue = input.toLowerCase(); assertEquals(expected, actualValue); }
@CsvFileSource
For example, we could use a CSV file like this:
input,expected test,TEST tEst,TEST Java,JAVAWe can load the CSV file and ignore the header column with @CsvFileSource:
@ParameterizedTest @CsvFileSource(resources = "/data.csv", numLinesToSkip = 1) void toUpperCase_ShouldGenerateTheExpectedUppercaseValueCSVFile( String input, String expected) { String actualValue = input.toUpperCase(); assertEquals(expected, actualValue); }
@MethodSource (Custom)
@ParameterizedTest @MethodSource("provideStringsForIsBlank") void isBlank_ShouldReturnTrueForNullOrBlankStrings(String input, boolean expected) { assertEquals(expected, Strings.isBlank(input)); }private static Stream<Arguments> provideStringsForIsBlank() { return Stream.of( Arguments.of(null, true), Arguments.of("", true), Arguments.of(" ", true), Arguments.of("not blank", false) ); }