Home > Software engineering >  Function<T, R> as additional argument in Junit 5
Function<T, R> as additional argument in Junit 5

Time:11-27

I am trying to pass test arguments to JUnit 5 that include Java's Function<T, R> interface type as shown in the following code snippet. I am getting a "Target type of a lambda conversion must be an interface" error because JUnit 5's Arguments type uses an Object array to store the parameters.

  @ParameterizedTest(name = "Test description: {0}")
  @MethodSource("generateArguments")
  void passFunctionAsAnArgumentTest(final String description, final Function<String, String> testMethod) {

    // Fetch initial preactivation value.
    final String result = testMethod.apply("input");
    assertThat(result, is("expected"));
  }

  private static Stream<Arguments> generateArguments() {

    return Stream.of(
        // Error: "Target type of a lambda conversion must be an interface".
        Arguments.of("Return 'expected' if argument is 'input'", (String input) -> generateStringFromInput(input))
    );
  }

  private static String generateStringFromInput(final String input) {

    return input.equals("input") ? "expected" : "wrong";
  }

If I generate a stream that only uses the Function<T, R> interface type the test compiles and runs fine.

  @ParameterizedTest(name = "No test description :(")
  @MethodSource("generateStream")
  void passFunctionAsAnArgumentTest(final Function<String, String> testMethod) {

    // Fetch initial preactivation value.
    final String result = testMethod.apply("input");
    assertThat(result, is("expected"));
  }

  private static Stream<Function<String, String>> generateStream() {

    return Stream.of(
        JUnitFeatureTest::generateStringFromInput
    );
  }

  private static String generateStringFromInput(final String input) {

    return input.equals("input") ? "expected" : "wrong";
  }

Obviously the actual code is a bit more complex. The reason why I want to pass functions instead of test data objects is because we call different methods with a different set of parameters. It is just a lot tidier to encapsulate that in helper methods.

CodePudding user response:

You need to tell the compiler which sort of lambda you intend to implent.
So you need to cast your lambda to a Function<String, String> like this:

private static Stream<Arguments> generateArguments() {
  return Stream.of(
      Arguments.of(
          "Return 'expected' if argument is 'input'",
          (Function<String, String>) JUnitFeatureTest::generateStringFromInput
      )
  );
}

or this

private static Stream<Arguments> generateArguments() {
  return Stream.of(
      Arguments.of(
          "Return 'expected' if argument is 'input'", 
          (Function<String, String>) input -> generateStringFromInput(input)
      )
  );
}
  • Related