There was a time when I thought that the @Nested
test was the best choice when it came to JUnit 5, but when I started using @ParameterizedTest
, I got used to it so much that I thought "What was that in JUnit 4?" feel well. This alone can recommend migration.
ValueSource
Parameters are specified using the @ValueSource
annotation. Depending on the parameter type, there are ʻints,
strings, and
doubles` properties.
@ParameterizedTest
@ValueSource(ints = {1, 2, 100})
void positiveNumber(int n) {
assertTrue(isPositiveNumber(n));
}
@ParameterizedTest
@ValueSource(strings = {"Java", "java", "JAVA"})
void upperCase(String s) {
assertEquals("JAVA", s.toUpperCase());
}
When run in the IDE, the test results for each parameter are fed back in an easy-to-understand manner. IntelliJ IDEA also allows you to rerun the test for certain parameters.
The parameters that can be specified with @ValueSource
are limited to primitive systems, but implicit type conversion from String is supported for other commonly used types. This is insanely useful if you want to write a date test.
@ParameterizedTest
@ValueSource(strings = {"2016-01-01", "2020-01-01", "2020-12-31"})
void leapYear(LocalDate date) {
assertTrue(date.isLeapYear());
}
For more information on supported type conversions, see the Official Documentation (https://junit.org/junit5/docs/5.3.0/user-guide/#writing-tests-parameterized-tests-argument-conversion-implicit). please refer to.
MethodSource
While @ValueSource
can only give one parameter at a time, using @MethodSource
allows you to:
By giving the expected value as a parameter, you can easily write Table Driven Test as recommended by Go language. This is especially useful if you want to write tests for utility methods that just return a String or boolean.
@ParameterizedTest
@MethodSource("japaneseDateProvider")
void japaneseEra(JapaneseDate date, String expected) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("G").withLocale(Locale.JAPAN);
assertEquals(expected, formatter.format(date));
}
static Stream<Arguments> japaneseDateProvider() {
return Stream.of(
arguments(JapaneseDate.of(1989, 1, 7), "Showa"),
arguments(JapaneseDate.of(1989, 1, 8), "Heisei"),
arguments(JapaneseDate.of(2019, 4, 30), "Heisei"),
arguments(JapaneseDate.of(2019, 5, 1), "Reiwa")
);
}
CsvSource
@MethodSource
has to define different methods one by one, and there is a little noise other than test data. If you don't need your own type, you can use @CsvSource
to work around this issue.
Each field separated by a comma is a parameter. The Implicit Type Conversion (#Implicit Type Conversion) mechanism described earlier automatically maps a String to a method argument type.
@ParameterizedTest
@CsvSource({
"1989-01-07,Showa",
"1989-01-08,Heisei",
"2019-04-30,Heisei",
"2019-05-01,Reiwa"
})
void japaneseEra(LocalDate date, String expected) {
JapaneseDate d = JapaneseDate.from(date);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("G").withLocale(Locale.JAPAN);
assertEquals(expected, formatter.format(d));
}
Since enums are also subject to implicit type conversion, you can write code like this: It's easy and very convenient, but I think it's easy to forget to modify the scope of influence when refactoring the name of an enum constant name. I can't say anything because I haven't been to that scene yet.
@ParameterizedTest
@CsvSource({
"JANUARY, false, 31",
"FEBRUARY, false, 28",
"FEBRUARY, true, 29"
})
void daysOfMonth(Month month, boolean leapYear, int expected) {
assertEquals(expected, month.length(leapYear));
}
If you want to include an empty string, enclose it in single quotes like " 2,'', true "
. On the other hand, if you do " 2,, true "
without single quotes, it will be null, so be careful.
We have briefly introduced the parameterized tests that have been revamped in JUnit 5. The parameterization test of JUnit 4 was difficult to understand, and there were many scenes where I wrote a loop to avoid it, but I recommend this because it is very intuitive to use in JUnit 5.
Recommended Posts