如何在JUnit 5中使用String数组进行参数化

我想编写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 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; 

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

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

 static Stream 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

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

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

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

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

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

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

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

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

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

  2. 你真的想要一个可变大小的字符串数组。 在这种情况下,您可以使用@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指示的Explicit Converter类:

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

Sormuras解决方案的另一种选择是使用注释@ArgumentsSource ,它以非常类似的方式工作:

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

仍然,将String[]Object看起来很奇怪,而且我有一种解决方法,而不是漂亮的设计。