How to parameterize with String arrays in JUnit 5

13,762

Solution 1

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

Solution 2

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:

  1. you are interested in a fixed number of strings (so not really need for an array). You can use @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)

  1. you want really a variable size array of Strings. In this case you can use @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*");
      }
    }
Share:
13,762
Vít Kotačka
Author by

Vít Kotačka

Working 10+ years with enterprise Java, but I fell in love with Golang and Clojure. I am an avid reader - usually I read about 50 books a year, one third of them on software engineering topics. I am a distance runner too - my long time plan is to run two marathons a year. So, programming, reading and running are my passions. And very often, they interlace.

Updated on June 06, 2022

Comments

  • Vít Kotačka
    Vít Kotačka almost 2 years

    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?

  • Vít Kotačka
    Vít Kotačka over 6 years
    This works, thanks. But casting to Object looks strange.
  • Sormuras
    Sormuras over 6 years
    Due to the "..."-varargs nature of the factory method. Same as with "List.of()": List.of((Object) new String[]{"1", "2"}) is not equal to List.of(new String[]{"1", "2"})
  • Sormuras
    Sormuras over 6 years
    IDEA notes: Confusing argument 'new String[] { "1", "2" }', unclear if a varargs or non-varargs call is desired.