In this section, we will explore the @ParameterizedTest annotation in JUnit, which allows us to run the same test multiple times with different parameters. This is particularly useful for testing methods with a variety of inputs and expected outputs.

Key Concepts

  1. Parameterized Tests: Tests that run multiple times with different sets of parameters.
  2. @ParameterizedTest Annotation: Marks a method as a parameterized test.
  3. Source Annotations: Annotations like @ValueSource, @CsvSource, and @MethodSource that provide the parameters for the test.

Setting Up a Parameterized Test

Step-by-Step Guide

  1. Add JUnit 5 Dependency: Ensure you have JUnit 5 in your project dependencies.
  2. Create a Test Class: Define a class where you will write your parameterized tests.
  3. Use @ParameterizedTest: Annotate your test method with @ParameterizedTest.
  4. Provide Parameters: Use source annotations to provide the parameters for the test.

Example

Let's create a simple parameterized test to check if a number is even.

Step 1: Add JUnit 5 Dependency

Ensure your pom.xml (for Maven) or build.gradle (for Gradle) includes JUnit 5.

Maven:

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

Gradle:

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

Step 2: Create a Test Class

Create a new class for your tests.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class NumberTest {

    @ParameterizedTest
    @ValueSource(ints = {2, 4, 6, 8, 10})
    void testIsEven(int number) {
        assertTrue(isEven(number));
    }

    boolean isEven(int number) {
        return number % 2 == 0;
    }
}

Explanation

  • @ParameterizedTest: Marks the testIsEven method as a parameterized test.
  • @ValueSource: Provides the parameters for the test. In this case, it provides an array of integers.
  • assertTrue: Asserts that the condition is true. Here, it checks if the number is even.

Using Different Source Annotations

@CsvSource

Use @CsvSource to provide multiple parameters.

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

import static org.junit.jupiter.api.Assertions.assertEquals;

public class MathTest {

    @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. Each set is a comma-separated string.
  • assertEquals: Asserts that the expected value is equal to the actual value.

@MethodSource

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.assertTrue;

public class StringTest {

    @ParameterizedTest
    @MethodSource("stringProvider")
    void testIsNotEmpty(String str) {
        assertTrue(str != null && !str.isEmpty());
    }

    static Stream<String> stringProvider() {
        return Stream.of("apple", "banana", "cherry");
    }
}

Explanation

  • @MethodSource: Specifies a method that provides the parameters. The method must return a Stream, Iterable, Iterator, or array.
  • assertTrue: Asserts that the string is not null and not empty.

Practical Exercise

Exercise

Create a parameterized test to check if a string is a palindrome.

  1. Create a new test class PalindromeTest.
  2. Write a method isPalindrome that checks if a string is a palindrome.
  3. Use @ParameterizedTest and @ValueSource to test the method with different strings.

Solution

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

import static org.junit.jupiter.api.Assertions.assertTrue;

public class PalindromeTest {

    @ParameterizedTest
    @ValueSource(strings = {"madam", "racecar", "radar"})
    void testIsPalindrome(String str) {
        assertTrue(isPalindrome(str));
    }

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

Explanation

  • @ValueSource: Provides an array of strings to test.
  • isPalindrome: Checks if the string is equal to its reverse.

Common Mistakes and Tips

  • Incorrect Parameter Types: Ensure the parameter types in the test method match those provided by the source annotation.
  • Null Values: Handle null values appropriately in your tests.
  • Complex Parameters: For complex parameters, consider using @MethodSource for better readability and maintainability.

Conclusion

In this section, we learned how to use the @ParameterizedTest annotation in JUnit to run tests with different parameters. We explored various source annotations like @ValueSource, @CsvSource, and @MethodSource to provide parameters. By using parameterized tests, we can write more comprehensive and efficient test cases, ensuring our code is robust and reliable.

© Copyright 2024. All rights reserved