If you really want to pass in a delimited list as part of the CSV (for instance, maybe it really does make the code look a lot cleaner), you can use the explicit conversion functionality of JUnit using a custom 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(";"));
}
}
}
Fully generic list conversion
If you're planning on using the list conversion in multiple places with different element types in each place (e.g. List<String>
, List<Integer>
, List<LocalDate>
), you could create a generic argument converter that delegates to a different argument converter to convert the different element types).
The following is an example that uses the Google Guava TypeToken
class to determine the list element type, and the built-in internal JUnit DefaultArgumentConverter
to perform the element conversions:
@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();
}
}