Use null values in JUnit 5 parameterized tests

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!

Short URL for this post: https://wp.me/p4nxik-3bT
Roland Krüger

About Roland Krüger

Software Engineer at Orientation in Objects GmbH. Find me on Google+, follow me on Twitter.
This entry was posted in Java and Quality and tagged , . Bookmark the permalink.

One Response to Use null values in JUnit 5 parameterized tests

  1. Pingback: Java Testing Weekly 44 / 2018

Leave a Reply