Parameterized Tests

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 5 min

TL;DR

  • Parameterized Tests allow you to run the exact same @Test method multiple times with different sets of input data.
  • They eliminate the need to write 10 duplicate test methods just to check edge cases.
  • In JUnit 5, you use @ParameterizedTest instead of @Test, combined with a source like @ValueSource or @MethodSource.

Concept

If you are testing an isPalindrome(String) method, you want to test “racecar” (true), “radar” (true), “hello” (false), and "" (true).
Without parameterized tests, you either write 4 separate methods (testPalindromeRacecar(), etc.), or you write one test with 4 assertTrue/assertFalse lines. If the first assertion fails, the test stops, and the remaining 3 are never checked!

A Parameterized Test solves this. You define the method once, declare the inputs as method parameters, and provide an array of data. JUnit will execute the test method 4 separate times, generating 4 independent test results.

Examples

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

class StringUtilsTest {

    // 1. Single Parameter (ValueSource)
    // This test will run 3 times, once for each string.
    @ParameterizedTest
    @ValueSource(strings = { "racecar", "radar", "madam" })
    void isPalindrome_ShouldReturnTrueForPalindromes(String word) {
        assertTrue(StringUtils.isPalindrome(word));
    }

    // 2. Multiple Parameters (CsvSource)
    // Allows you to pass the input AND the expected output!
    @ParameterizedTest
    @CsvSource({
        "hello, false",
        "racecar, true",
        "'', true", // empty string
        "A, true"
    })
    void isPalindrome_ShouldReturnCorrectResult(String word, boolean expected) {
        assertEquals(expected, StringUtils.isPalindrome(word));
    }
}

Interview Questions

Q: What is @MethodSource?
A: While @ValueSource is great for simple primitives, you often need to test complex objects (like passing a User object into a test). You cannot put objects inside annotations. @MethodSource tells JUnit to call a specific static method in your test class. That method returns a Stream<Arguments>, allowing you to programmatically generate and pass complex objects, lists, or database entities directly into your parameterized test.

Q: What is the advantage of a Parameterized Test over a for loop inside a @Test?
A: If you put a for loop inside a standard @Test and the assertion fails on the 2nd iteration, the test immediately throws an exception and halts. You will never know if iterations 3, 4, and 5 would have passed or failed.
A @ParameterizedTest treats every input as a completely independent test case. If input 2 fails, JUnit logs the failure, resets the class, and continues running inputs 3, 4, and 5, giving you a complete report of exactly what works and what doesn’t.