Parameterized tests allow you to run the same test multiple times with different inputs. This is particularly useful for testing functions that should behave the same way for a variety of inputs. In this section, we will cover how to create parameterized tests in JUnit.

Key Concepts

  1. Parameterized Tests: Tests that run multiple times with different sets of parameters.
  2. @ParameterizedTest: Annotation used to denote a parameterized test.
  3. @ValueSource: Annotation used to provide a single array of values to the parameterized test.
  4. @CsvSource: Annotation used to provide multiple sets of values in CSV format.
  5. @MethodSource: Annotation used to provide a method that returns a stream of arguments.

Step-by-Step Guide

  1. Adding Dependencies

First, ensure you have the necessary dependencies in your pom.xml (for Maven) or build.gradle (for Gradle) file.

Maven:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-params</artifactId>
    <version>5.8.1</version>
    <scope>test</scope>
</dependency>

Gradle:

testImplementation 'org.junit.jupiter:junit-jupiter-params:5.8.1'

  1. Creating a Simple Parameterized Test

Let's start with a simple example using @ValueSource.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;

public class ParameterizedTestExample {

    @ParameterizedTest
    @ValueSource(strings = {"racecar", "radar", "level"})
    void testPalindrome(String candidate) {
        assertTrue(isPalindrome(candidate));
    }

    boolean isPalindrome(String str) {
        return str.equals(new StringBuilder(str).reverse().toString());
    }
}

Explanation:

  • @ParameterizedTest indicates that the method is a parameterized test.
  • @ValueSource(strings = {"racecar", "radar", "level"}) provides the parameters for the test.
  • The testPalindrome method will run three times, once for each string in the @ValueSource.

  1. Using @CsvSource for Multiple Parameters

If you need to pass multiple parameters, you can use @CsvSource.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class CsvSourceExample {

    @ParameterizedTest
    @CsvSource({
        "1, 1, 2",
        "2, 3, 5",
        "3, 5, 8"
    })
    void testAddition(int a, int b, int expected) {
        assertEquals(expected, add(a, b));
    }

    int add(int a, int b) {
        return a + b;
    }
}

Explanation:

  • @CsvSource provides multiple sets of parameters in CSV format.
  • The testAddition method will run three times with different sets of parameters.

  1. Using @MethodSource for Complex Parameters

For more complex scenarios, you can use @MethodSource to provide parameters from a method.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MethodSourceExample {

    @ParameterizedTest
    @MethodSource("provideStringsForIsBlank")
    void testIsBlank(String input, boolean expected) {
        assertEquals(expected, isBlank(input));
    }

    static Stream<Arguments> provideStringsForIsBlank() {
        return Stream.of(
            Arguments.of(null, true),
            Arguments.of("", true),
            Arguments.of("  ", true),
            Arguments.of("not blank", false)
        );
    }

    boolean isBlank(String str) {
        return str == null || str.trim().isEmpty();
    }
}

Explanation:

  • @MethodSource("provideStringsForIsBlank") specifies the method that provides the parameters.
  • The provideStringsForIsBlank method returns a stream of Arguments.
  • The testIsBlank method will run four times with different sets of parameters.

Practical Exercise

Exercise: Create a Parameterized Test for a Multiplication Function

  1. Create a method multiply(int a, int b) that returns the product of a and b.
  2. Write a parameterized test using @CsvSource to test the multiply method with the following pairs of values:
    • (2, 3, 6)
    • (4, 5, 20)
    • (6, 7, 42)

Solution

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
import static org.junit.jupiter.api.Assertions.assertEquals;

public class MultiplicationTest {

    @ParameterizedTest
    @CsvSource({
        "2, 3, 6",
        "4, 5, 20",
        "6, 7, 42"
    })
    void testMultiply(int a, int b, int expected) {
        assertEquals(expected, multiply(a, b));
    }

    int multiply(int a, int b) {
        return a * b;
    }
}

Explanation:

  • The @CsvSource annotation provides the parameters for the test.
  • The testMultiply method will run three times with different sets of parameters.

Conclusion

In this section, we learned how to create parameterized tests in JUnit using @ValueSource, @CsvSource, and @MethodSource. Parameterized tests are a powerful feature that allows you to run the same test with different inputs, making your tests more comprehensive and reducing code duplication. In the next section, we will explore the @ParameterizedTest annotation in more detail.

© Copyright 2024. All rights reserved