I would like to write JUnit 5 parametrized test which takes string array (String[]
) as a parameter:
@ParameterizedTest
@MethodSource("stringArrayProvider")
void parseFirstAndSecondInt(String[] args) {
Arguments arguments = new Arguments(args);
assertEquals(1, arguments.getFirst());
assertEquals(2, arguments.getSecond());
}
I'm not sure, how to provide a collection/stream/iterator of string arrays. I've unsuccessfully tried following approach with @MethodSource
annotation
static Stream<String[]> stringArrayProvider() {
return Stream.of(
new String[]{"1", "2"},
new String[]{"1", "2", "3"});
}
but I'm receiving this exception:
org.junit.jupiter.params.converter.ArgumentConversionException:
No implicit conversion to convert object of type java.lang.String to type [Ljava.lang.String;
What would be a good design/solution to have such kind of parameterized test?
JUnit 5, the next generation of JUnit, facilitates writing developer tests with shiny new features. One such feature is parameterized tests. This feature enables us to execute a single test method multiple times with different parameters.
JUnit allows you to use parameters in a tests class. This class can contain multipletest methods and each method is executed with the different parameters provided. It helps developers save time when executing the same tests which differ only in their inputs and expected results.
Use the Arguments.of()
factory from org.junit.jupiter.params.provider.Arguments
to wrap your arguments:
static Stream<Arguments> stringArrayProvider() {
return Stream.of(
Arguments.of((Object) new String[]{"1", "2"}),
Arguments.of((Object) new String[]{"1", "2", "3"})
);
}
For details see http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests
First one general rule of thumb that I use:
use @ArgumentSource
(your solution) when the same generated test cases can be used by more than one Test Class
use @MethodSource
(Sormuras' solution) when the same generated test cases can be used by more than one Test Method (in the same class)
otherwise try to keep the source for test cases as local as possible to the method that uses them
In this last situation I envision two simple possibilities:
@CsvSource
Here there is an example for two strings (possibly including commas too).
@ParameterizedTest
@CsvSource({ "foo, 1", "bar, 2", "'baz, qux', 3" })
void testWithCsvSource(String first, String second) {
assertNotNull(first);
assertNotEquals(0, second);
}
Note that in this case, if the various elements are not really strings they can be probably automatically parsed to the correct types (e.g., in your question it seems that you want integers)
@ValueSource
and then convert its content to String[]directly:
@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
...
}
or with an Explicit Converter class indicated by @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*");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With