如何在 JUnit 5 中使用字符串数组进行参数化

2022-09-02 04:00:36

我想编写以字符串数组()作为参数的JUnit 5参数化测试:String[]

@ParameterizedTest
@MethodSource("stringArrayProvider")
void parseFirstAndSecondInt(String[] args) {
    Arguments arguments = new Arguments(args);

    assertEquals(1, arguments.getFirst());
    assertEquals(2, arguments.getSecond());
}

我不确定,如何提供字符串数组的集合/流/迭代器。我尝试过以下带有注释的方法,但没有成功@MethodSource

static Stream<String[]> stringArrayProvider() {
    return Stream.of(
            new String[]{"1", "2"},
            new String[]{"1", "2", "3"});
}

但是我收到这个例外:

org.junit.jupiter.params.converter.ArgumentConversionException:
    No implicit conversion to convert object of type java.lang.String to type [Ljava.lang.String;

拥有这种参数化测试的好设计/解决方案是什么?


答案 1

使用 factory from 来包装参数:Arguments.of()org.junit.jupiter.params.provider.Arguments

static Stream<Arguments> stringArrayProvider() {
    return Stream.of(
            Arguments.of((Object) new String[]{"1", "2"}),
            Arguments.of((Object) new String[]{"1", "2", "3"})
    );
}

有关详细信息,请参阅 http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests


答案 2

我使用的第一个一般经验法则:

  • 当多个测试类可以使用相同生成的测试用例时,使用(您的解决方案)@ArgumentSource

  • 使用(Sormuras的解决方案)当相同的生成的测试用例可以被多个测试方法(在同一类中)使用时@MethodSource

  • 否则,请尝试将测试用例的源代码尽可能地保留在使用它们的方法的本地

在最后一种情况下,我设想了两种简单的可能性:

  1. 你对固定数量的字符串感兴趣(所以不是真的需要数组)。您可以使用@CsvSource

这里有一个两个字符串的示例(可能还包括逗号)。

    @ParameterizedTest
    @CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
    void testWithCsvSource(String first, String second) {
        assertNotNull(first);
        assertNotEquals(0, second);
    }

请注意,在这种情况下,如果各种元素不是真正的字符串,它们可能会被自动解析为正确的类型(例如,在您的问题中,似乎您需要整数)

  1. 你真的想要一个可变大小的字符串数组。在这种情况下,您可以使用然后将其内容转换为 String[]@ValueSource

径直:

    @ParameterizedTest
    @ValueSource(strings = {"1, 2",
                            "1, 2, 3"})
    void testWithArrayOfStrings(String arg) {       // the single csv String parameter
      String[] arrayParam = arg.split("\\s*,\\s*"); // is converted to an array of Strings
      ...
    }

或使用由 @ConvertWith 指示的显式转换器类:

    @ParameterizedTest
    @ValueSource(strings={"1, 2", "1, 2, 3"})
    void testWithArrayOfStrings(@ConvertWith(CSVtoArray.class)String... arg) 
    {
      ...
    }

    public static class CSVtoArray extends SimpleArgumentConverter {
      @Override
      protected Object convert(Object source, Class<?> targetType) throws ArgumentConversionException {
        String s = (String) source;
        return s.split("\\s*,\\s*");
      }
    }