Parameterized Test with two Arguments in JUnit 5 jupiter
Asked Answered
C

3

96

How can I write a parameterized test with two arguments in JUnit 5 jupiter? The following does not work (compile error):

@ParameterizedTest
@ValueSource(strings = { "a", "b", "foo" })
@ValueSource(ints = { 1, 2, 3 })
public void test(String arg1, int arg2) {
    // ...
}
Controversy answered 28/4, 2020 at 15:4 Comment(0)
H
166

Here are two possibilities to achieve these multi argument test method calls.

The first (testParameters) uses a CsvSource to which you provide a comma separated list (the delimiter is configurable) and the type casting is done automatically to your test method parameters.

The second (testParametersFromMethod) uses a method (provideParameters) to provide the needed data.

@ParameterizedTest
@CsvSource({"a,1", "b,2", "foo,3"})
public void testParameters(String name, int value) {
    System.out.println("csv data " + name + " value " + value);
}

@ParameterizedTest
@MethodSource("provideParameters")
public void testParametersFromMethod(String name, int value) {
    System.out.println("method data " + name + " value " + value);
}

private static Stream<Arguments> provideParameters() {
    return Stream.of(
            Arguments.of("a", 1),
            Arguments.of("b", 2),
            Arguments.of("foo", 3)
    );
}

The output of these test methods are:

Running ParameterTest
csv data a value 1
csv data b value 2
csv data foo value 3
method data a value 1
method data b value 2
method data foo value 3
Horrible answered 28/4, 2020 at 15:38 Comment(3)
Thanks a lot. Is there a way to test the cross product ("a,1","a,2","a,3","b,1","b,2",...) without writing every combination?Controversy
For this the method approach will do the job. In provideParameters you could build up every combination you want.Horrible
@Controversy There is already an issue about that: github.com/junit-team/junit5/issues/1427.Karb
I
3

Best Practices Parameterized Test!!

Consider a simple function to test:

public static boolean isDivisibleBy(int dividend, int divisor){
    return dividend % divisor == 0;
}

When generating JUnit5 Parameterized Test case:

  1. Use @DisplayName annotation with a message.

  2. Use @ParameterizedTest with name argument.

  3. Use @ParameterizedTest(name = " with {0}..{N} ") to point to @CsvSource's values.

  4. Use @CsvSource({"key1,value1", "key2,value2", "key3,value3", .. }) without worry of conversion. This mechanism is based on implicit converters that can interpret a String into another type, such as int. This particular example may not seem that impressive, but it works with a lot of very useful common types, such as File, Path, BigDecimal, Date, Time, enum and URL.

  5. Don't use @Test along with @ParameterizedTest.

Example:

@DisplayName("Divide Test Cases 😎")
@ParameterizedTest(name = "{0} is multiple of {1}")
@CsvSource({"2,2", "4,2", "7,3"})
void shouldReturnTrueForVariousDivisiblePairs(int givenDividend, int givenDivisor) {
    assertTrue(isDivisibleBy(givenDividend, givenDivisor));
}

Pretty Output Log:

Output

Insurer answered 21/1 at 16:18 Comment(0)
I
0

Here is a solution using Kotlin language:

class MyTests {
    @ParameterizedTest
    @MethodSource("generateArgs")
    fun myTest(myArg: Pair<String, Int>) {
        val (name, age) = myArg // Destructuring; could instead use myArg.first and myArg.second
        println("$name $age")
    }

    companion object {
        @JvmStatic
        fun generateArgs() = listOf (
            "A" to 1,
            "B" to 2,
            "C" to 3
        )
    }
}
Intramundane answered 7/9, 2023 at 11:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.