22 April 2017

This is a follow up to my previous post about data injection with JUnit. The JUnit team release milestone 4 of JUnit 5 on 1st of April 2017, which added a new module junit-jupiter-params to support parameterized tests within JUnit Jupiter.

The simplest way to provide different parameters to a test is via @ValueSource:

  static Collection<Object[]> data() {
    return Arrays.asList(new Object[][]{
      {17, false},
      {22, true}
    });
  }

  @ParameterizedTest
  @MethodSource(names = "data")
  void personIsAdult(int age, boolean isAdult) {
    assertThat(new Person(age).isAdult(), is(isAdult));
  }

In the previous post, we aimed for providing the data via a method which is possible with @MethodSource:

  static Stream<Arguments> arguments() {
    return Stream.of(
      ObjectArrayArguments.create(17, false),
      ObjectArrayArguments.create(22, true)
    );
  }

  @ParameterizedTest
  @MethodSource(names = "arguments")
  void personIsAdultWithArguments(int age, boolean isAdult) {
    assertThat(new Person(age).isAdult(), is(isAdult));
  }

There’re several other argument sources supported, like enum, CSV, CSV file, and others. Please consult the JUnit docs for details.

It seems to be already feature complete. At least the JUnitParams team thinks so as they gave up supporting JUnit 5.

But there is still room for improvement. Java 5 Generics brought us the next level of compile time type checking. Why not leverage this here? In both of the above snippets nothing prevents us from providing arguments of the wrong types or even different number of arguments.

What about the following?

  static Stream<TypedArguments2<Integer, Boolean>> arguments() {
    return Stream.of(
      TypedArguments.create(17, false),
      TypedArguments.create(22, true)
    );
  }

  @ParameterizedTest
  @MethodSource(names = "arguments")
  void personIsAdultWithArguments(int age, boolean isAdult) {
    assertThat(new Person(age).isAdult(), is(isAdult));
  }

With the help of Generics, TypedArguments makes sure, that the provided parameters conform to the declaration of the arguments method. Both in number and type.

To achieve this I created small library junit-jupiter-typed-params as an add-on to junit-jupiter-params.

Do you think this is helpful?