Как перенести TestNG @dataProvider в JUnit Jupiter @ParameterizedTest

#testng #junit5 #testng-dataprovider #junit-jupiter

#testng #junit5 #testng-dataprovider #junit-jupiter

Вопрос:

У меня есть модульные тесты с использованием TestNG, которые я пытаюсь перенести в JUnit Jupiter (JUnit 5), и мне интересно, какой лучший способ сделать:

TestNG:

 @DataProvider
public Object[][] invalidPortNumbers() {
    return new Object[][] {
            { "--http", "" },
            { "--http", "-42" },
            { "--http", "0" },
            { "--http", "not_a_port_number" },
            { "--https", "67000" }
    };
}

@Test(dataProvider = "invalidPortNumbers",
      expectedExceptions = ParameterException.class,
      expectedExceptionsMessageRegExp = ".* is not valid port number .*")
public void shouldFailToValidatePortNumber(final String... args) {
    new CommandLineParser(args);
}
  

Я видел, что, перейдя на JUnit Jupiter, я могу сделать:

 static Stream<Arguments> invalidPortNumbers2() {
    return Stream.of(
            Arguments.of((Object) new String[] { "--http", "-42" }),
            Arguments.of((Object) new String[] { "--http", "0" }),
            Arguments.of((Object) new String[] { "--http", "not_a_port_number" }),
            Arguments.of((Object) new String[] { "--https", "67000" })
    );
}

@ParameterizedTest
@MethodSource("invalidPortNumbers2")
void shouldFailToValidatePortNumber(final String... args) {
    assertThatThrownBy(() -> new CommandLineParser(args))
            .isInstanceOf(ParameterException.class)
            .hasMessageMatching(".* is not valid port number .*");
}
  

Есть ли какой-либо другой способ упростить это и сохранить предыдущую структуру dataProvider, чтобы минимизировать изменения?

Спасибо.

Комментарии:

1. Что произойдет, если вы создадите свой существующий invalidPortNumbers() метод static и ссылаетесь на него @MethodSource ?

2. Я получил следующее исключение: org.junit.jupiter.api.extension.ParameterResolutionException: Error converting parameter at index 0: No implicit conversion to convert object of type java.lang.String to type [Ljava.lang.String;

Ответ №1:

При параметризованных тестах в JUnit Jupiter, если возвращаемый тип метода, на который ссылается via @MethodSource , представляет собой двумерный массив, значения внутренних массивов будут переданы в качестве нескольких аргументов при вызове одного метода тестирования. Это означает, что нет простого способа перенести метод тестирования, который принимает переменные аргументы (или явный массив) из TestNG @DataProvider в JUnit Jupiter @MethodSource .

Это invalidPortNumbers2() подходящее решение для этого ограничения, но есть и другие обходные пути, которые вы можете предпочесть.


Обновленный ответ:

Самый простой способ обработать все аргументы как единый массив — через ArgumentsAccessor API.

Если вы создаете свой существующий invalidPortNumbers() метод static , вы можете использовать его «как есть» и преобразовать аргументы в массив следующим образом.

 @ParameterizedTest
@MethodSource("invalidPortNumbers")
void shouldFailToValidatePortNumber(ArgumentsAccessor accessor) {
    Object[] args = accessor.toArray();
    // Use args ...
}
  

Хотя в JUnit Jupiter вы можете обнаружить, что использование a @CsvSource предпочтительнее, чем использование @MethodSource для таких случаев использования. Итак, для достижения той же цели вы можете переписать свой тест следующим образом и избавиться от invalidPortNumbers() метода.

 @ParameterizedTest
@CsvSource({
    "--http, ''",
    "--http, -42",
    "--http, 0",
    "--http, not_a_port_number",
    "--https, 67000"
})
void shouldFailToValidatePortNumber(ArgumentsAccessor accessor) {
    Object[] args = accessor.toArray();
    // Use args ...
}
  

Оригинальный ответ:

Для начала, следующий служебный метод поможет упростить вещи (объявленный в классе с именем VarArgsParamsTests , но может быть перемещен в общий служебный класс). Обратите внимание, что arguments() статически импортируется через org.junit.jupiter.params.provider.Arguments.arguments .

 static Arguments arrayArguments(String... array) {
    return arguments((Object) array);
}
  

Учитывая это, если вы хотите сохранить существующий invalidPortNumbers() метод с как можно меньшими изменениями, вы можете переопределить его сигнатуру как static String[][] invalidPortNumbers() и ввести следующий метод, на который вы фактически ссылаетесь @MethodSource .

 static Stream<Arguments> invalidPortNumbersArguments() {
    return Arrays.stream(invalidPortNumbers()).map(VarArgsParamsTests::arrayArguments);
}
  

Если вы хотите еще больше изменить существующий invalidPortNumbers() метод, вы можете изменить его на следующий, который также использует метод arrayArguments() утилиты.

 static Stream<Arguments> invalidPortNumbers() {
    return Stream.of(
        arrayArguments("--http", ""),
        arrayArguments("--http", "-42"),
        arrayArguments( "--http", "0"),
        arrayArguments( "--http", "not_a_port_number"),
        arrayArguments( "--https", "67000")
    );
}
  

Комментарии:

1. Пожалуйста, обратите внимание, что я добавил решения, используя API ArgumentsAccessor.