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

How to parameterize with String arrays in JUnit 5

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

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

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

我不确定如何提供 collection/stream/iterator 字符串数组。我尝试使用 @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;

有什么好的 design/solution 进行这种参数化测试?

使用 org.junit.jupiter.params.provider.Arguments 中的 Arguments.of() 工厂来包装您的参数:

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

的替代方法是使用注释 @ArgumentsSource,其工作方式非常相似:

static class StringArrayProvider implements ArgumentsProvider {
    @Override
    public Stream<? extends Arguments> provideArguments(ExtensionContext context) throws Exception {
        return Stream.of(
                (Object) new String[]{"1", "2"},
                (Object) new String[]{"1", "2", "3"}).map(Arguments::of);
    }
}

尽管如此,将 String[] 转换为 Object 看起来很奇怪,我觉得这是解决方法而不是好的设计。

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

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

  • 使用@MethodSource)当相同生成的测试用例可以被多个测试方法使用时(在同一个class)

  • 否则尽量将测试用例的源代码保持在使用它们的方法的本地

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

  1. 您对固定数量的字符串感兴趣(因此实际上不需要数组)。您可以使用 @CsvSource

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

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

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

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

直接:

    @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 指示的显式转换器class:

    @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*");
      }
    }