JUnit 5 allows you to parameterize your tests so that the same test case is executed repeatedly with a varying set of test parameters. This is similar to the parameterized test feature of JUnit 4, except now these tests are much easier and much less cumbersome to write and maintain than in the old version of JUnit.
If you need to provide null
as a test argument value, however, there is a caveat which is described in this post.
JUnit 5 introduces the concept of argument sources. While in JUnit 4 you had to define a two-dimensional Object
array whose values were injected into the constructor of a parameterized test class, JUnit 5 now lets you inject the test values into each individual test method directly. By that, each test method of a test class can receive a distinct set of test data. To do that, you first annotate a test method with @ParameterizedTest
to indicate that this test is going to receive a series of test arguments. Next, you define the source of the test arguments by providing one of a number of source annotations. You can provide a list of primitive test arguments directly (@ValueSource
, @EnumSource
), define a argument generator method (@MethodSource
), specify test data encoded as comma-separated values (@CsvSource
, @CsvFileSource
), or define an arguments provider class (@ArgumentsSource
).
So, the easiest and most straight-forward way to define test arguments is to use @ValueSource
, which is handy if you only need a number of primitive values, such as a list of Strings or numbers. Using @ValueSource
might look like the following:
@ParameterizedTest @ValueSource(strings = {"foo", "bar", "baz"}) void testIsNotBlank(String testValue) { Assertions.assertFalse(Strings.isBlank(testValue)); }
However, if you need null
as one of the test values, you will run into problems. Trying to include null
in the list of test values like in the following example will give you a compiler error:
@ParameterizedTest @ValueSource(strings = {"", " ", null}) void isBlank(String testValue) { Assertions.assertTrue(Strings.isBlank(testValue)); }
The compiler will complain with the following message:
java: The value for annotation attribute org.junit.jupiter.params.provider.ValueSource.strings must be a constant expression
The reason for this is that Java requires all annotation parameters to be of a constant expression. Constant expressions are defined in the Java language specification. This list does not contain null
. So using null
in the @ValueSource
annotation is not allowed, even though the null
value is an element of an array.
There is no way around this limitation, so here is what you can do if you encounter this situation: use @MethodSource
instead of @ValueSource
to provide your test arguments.
A @MethodSource
is a static method that returns a Stream
of objects (or an Iterator
, Iterable
, or Object[]
). Since this Stream
is allowed to contain null
, you can use this approach as an alternative to @ValueSource
:
static Stream<String> blankStrings() { return Stream.of("", " ", null); } @ParameterizedTest @MethodSource("blankStrings") void isBlank(final String testValue) { Assertions.assertTrue(Strings.isBlank(testValue)); }
You define a static method returning a Stream
of arbitrary data. This method is then referenced by its name from the @MethodSource
annotation’s parameter. If you use an IDE with JUnit 5 support, such as IntelliJ IDEA, you can rely on the IDE to give you a hint when the @MethodSource
parameter value does not match any available static method with the correct signature.
Update: A solution to this problem might be added to JUnit 5 in milestone 5.4 M1: issue #1637 proposes the introduction of specific annotations which address this problem. When this is implemented, you will be able to use @ValueSource
with null
values after all. Thanks to Christian Stein for the hint!
Pingback: Java Testing Weekly 44 / 2018
CSVSource treats empty values (blank) as null.
Pingback: Was gibt es Neues im JUnit 5.6.0 Release? | techscouting through the java news
Since version 5.4 of JUnit there is @NullSource for this. The annotation can be used with @ValueSource together.
@ParameterizedTest
@NullSource
@ValueSource(strings = {“”, ” “})
void isBlank(String testValue) {
Assertions.assertTrue(Strings.isBlank(testValue));
}
Thank you, Roxy!
Your comment helped me a lot!