kotlin 如何将列表作为JUnit5的参数化测试参数传递?

6rqinv9w  于 2023-03-19  发布在  Kotlin
关注(0)|答案(3)|浏览(174)

我想使用三个参数来参数化JUnit5测试:x一个一个一个一个一个一个一个一个一个一个一个和x一个一个一个一个二个一个。
到目前为止,使用@CsvSource时没有任何运气,这是我的用例中传递参数的最方便的方式:
没有将类型为java.lang.String的对象转换为类型为java.util.List的隐式转换
实际测试为:

@ParameterizedTest()
@CsvSource(
  "2,1"
 )
fun shouldGetDataBit(first: Int, second: String, third: List<String>) {
    ...
}

你知道这是否可行吗?我在这里使用了Kotlin,但它应该是无关紧要的。

rdrgkggo

rdrgkggo1#

没有理由像StefanE建议的那样使用“黑客”。
在这一点上,我非常肯定Junit5测试参数不支持任何东西,除了原始类型和CsvSource只有一个允许混合类型。
实际上,JUnit Jupiter支持任何类型的参数,只是@CsvSource仅限于几个原语类型和String
因此,您不应使用@CsvSource,而应使用@MethodSource,如下所示。

@ParameterizedTest
@MethodSource("generateData")
void shouldGetDataBit(int first, String second, List<String> third) {
    System.out.println(first);
    System.out.println(second);
    System.out.println(third);
}

static Stream<Arguments> generateData() {
    return Stream.of(
        Arguments.of(1, "foo", Arrays.asList("a", "b", "c")),
        Arguments.of(2, "bar", Arrays.asList("x", "y", "z"))
    );
}
x8diyxa7

x8diyxa72#

提供第三个元素作为逗号分隔的字符串,并在测试中将该字符串拆分为List。
在这一点上,我非常肯定Junit5测试参数不支持任何东西,除了原始类型和CsvSource只有一个允许混合类型。

3vpjnl9f

3vpjnl9f3#

如果您真的希望将分隔列表作为CSV的一部分传入(例如,它可能真的使代码看起来干净很多),则可以使用JUnit的显式转换功能,使用定制的ArgumentConverter

@CsvSource({
        "First,A;B",
        "Second,C",
        ",",
        "'',''"
})
@ParameterizedTest
public void testMethod(String string,
                       @ConvertWith(StringToStringListArgumentConverter.class)
                       List<String> list) {
    // ...
}

@SuppressWarnings("rawtypes")
public static class StringToStringListArgumentConverter
        extends TypedArgumentConverter<String, List> {
    protected StringToStringListArgumentConverter() {
        super(String.class, List.class);
    }

    @Override
    protected List convert(String source)
            throws ArgumentConversionException {
        if (source == null) {
            return null;
        } else if (source.isEmpty()) {
            return List.of();
        } else {
            return List.of(source.split(";"));
        }
    }
}

完全通用的列表转换

如果您计划在多个位置使用列表转换,并且每个位置的元素类型不同(例如List<String>List<Integer>List<LocalDate>),则可以创建一个通用的参数转换器,委托不同的参数转换器来转换不同的元素类型。
下面的示例使用Google Guava TypeToken类来确定列表元素类型,并使用内置的内部JUnit DefaultArgumentConverter来执行元素转换:

@CsvSource({
        "First,1;2",
        "Second,3",
        ",",
        "'',''"
})
@ParameterizedTest
public void testMethod(String string,
                       @ConvertWith(StringToListArgumentConverter.class)
                       List<Integer> list) {
    // ...
}

public static class StringToListArgumentConverter
        implements ArgumentConverter {
    @Override
    public Object convert(Object source, ParameterContext context)
            throws ArgumentConversionException {
        if (source != null && !(source instanceof String)) {
            throw new ArgumentConversionException("Source must be a string");
        }
        if (!List.class.isAssignableFrom(context.getParameter().getType())) {
            throw new ArgumentConversionException("Target must be a list");
        }
        String sourceString = (String) source;
        if (sourceString == null) {
            return null;
        } else if (sourceString.isEmpty()) {
            return List.of();
        }

        @SuppressWarnings("UnstableApiUsage")
        Class<?> elementType =
                TypeToken.of(context.getParameter().getParameterizedType())
                        .resolveType(List.class.getTypeParameters()[0])
                        .getRawType();

        return Arrays.stream(sourceString.split(";"))
                .map(s -> DefaultArgumentConverter.INSTANCE
                        .convert(s, elementType))
                .toList();
    }
}

相关问题