Java 如何在JUnit5中使用字符串数组进行参数化

Java 如何在JUnit5中使用字符串数组进行参数化,java,unit-testing,junit,parameters,junit5,Java,Unit Testing,Junit,Parameters,Junit5,我想编写JUnit 5参数化测试,它将字符串数组(string[])作为参数: @ParameterizedTest @MethodSource(“stringArrayProvider”) void parseFirstAndSecondInt(字符串[]args){ 参数=新参数(args); assertEquals(1,arguments.getFirst()); assertEquals(2,arguments.getSecond()); } 我不确定如何提供字符串数组的集合/流/迭

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

@ParameterizedTest
@MethodSource(“stringArrayProvider”)
void parseFirstAndSecondInt(字符串[]args){
参数=新参数(args);
assertEquals(1,arguments.getFirst());
assertEquals(2,arguments.getSecond());
}
我不确定如何提供字符串数组的集合/流/迭代器。我用
@MethodSource
注释尝试了以下方法,但没有成功

静态流stringArrayProvider(){
回流(
新字符串[]{“1”,“2”},
新字符串[]{“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;
有这样一种参数化测试的好设计/解决方案是什么?

使用
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"})
    );
}
静态流

可以使用注释
@ArgumentsSource
,其工作方式非常类似:

静态类StringArrayProvider实现ArgumentsProvider{
@凌驾

公共流我使用的第一条一般经验法则:

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

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

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

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

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

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

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

  • 您确实需要一个大小可变的字符串数组。在这种情况下,您可以使用
    @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*");
      }
    }
    
    @ParameterizedTest
    @ValueSource(字符串={“1,2”,“1,2,3”})
    void testWithArrayOfString(@ConvertWith(CSVtoArray.class)字符串…arg)
    {
    ...
    }
    公共静态类CSVtoArray扩展了SimpleArgumentConverter{
    @凌驾
    受保护对象转换(对象源,类targetType)抛出ArgumentConversionException{
    字符串s=(字符串)源;
    返回s.split(“\\s*,\\s*”);
    }
    }
    

  • 这很有效,谢谢。但是强制转换到
    Object
    看起来很奇怪。由于工厂方法的“…”-varargs性质。与“List.of()”相同:
    List.of((Object)new String[]{“1”,“2”})
    不等于
    List.of(new String[]{“1”,“2”})
    IDEA注释:令人困惑的参数“new String[]{“1”,“2”}”,不清楚是否需要varargs或非varargs调用。
    @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*");
      }
    }