What is @ParameterizedTest in JUnit 5, and how does it differ from a plain @Test?
answer
- Template method run once per argument set
- Replaces @Test, needs a source annotation
- Independent invocation + report line per input
- Lives in junit-jupiter-params
- Loop-in-@Test stops at first failure; this doesn't
basics
~20 s@ParameterizedTest runs the same test method many times, once per set of input values. A plain @Test runs once with no arguments. You pair it with a source annotation (like @ValueSource) that supplies the values.
solid answer
~40 s@ParameterizedTest tells JUnit 5 to invoke one test method repeatedly, each time with a different set of arguments injected as method parameters. It replaces @Test (you use one or the other, never both) and must be paired with at least one argument source such as @ValueSource, @CsvSource, @MethodSource, or @EnumSource. Each argument set becomes a separate invocation with its own pass/fail result and its own entry in the test report, so a failure for one input does not hide the others. This removes copy-pasted near-identical tests and loops inside a single @Test (which stop at the first failed assertion). It lives in the junit-jupiter-params artifact. Display names come from a name template you can customize. It is ideal for testing the same logic across boundary values, equivalence classes, and edge cases.
code
java · 16 linesimport org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.junit.jupiter.api.Assertions.assertTrue;
class PalindromeTest {
@ParameterizedTest(name = "[{index}] \"{0}\" is a palindrome")
@ValueSource(strings = {"", "a", "aba", "racecar"})
void acceptsPalindromes(String s) {
assertTrue(isPalindrome(s));
}
static boolean isPalindrome(String s) {
return s.equals(new StringBuilder(s).reverse().toString());
}
}go deeper
Knows it runs the method once per input and must be paired with a source like @ValueSource instead of @Test.
Explains the independent-invocation/report-per-input benefit, names the common sources, and knows it lives in junit-jupiter-params.
Frames it as data-driven testing, contrasts with looping-in-@Test, customizes display names, and chooses the right source per case (literals vs CSV vs MethodSource).
Sets team conventions for parameterized vs example tests, weighs readability/maintenance of argument tables, and guides when to escalate to MethodSource/@ArgumentsSource or property-based testing.
## The problem it solves Unit testing means writing small automated checks that verify a piece of code behaves correctly. A common need is to verify the *same* behavior against *many* inputs — for example, that `isPalindrome` returns true for `""`, `"a"`, `"aba"`, and false for `"ab"`. Three bad ways to do this: 1. **Copy-paste** a `@Test` method per input — lots of duplicated code. 2. **Loop inside one `@Test`** — but a JUnit test method stops at the *first* failed assertion, so later inputs are never checked, and the report shows one test, not which input broke. 3. A parameterized test — the clean answer. ## What @ParameterizedTest is `@ParameterizedTest` is a JUnit 5 (JUnit Jupiter) annotation that marks a method as a **template** to be executed **multiple times**, once for each set of arguments. JUnit 5 is the current major version of JUnit, the standard Java testing framework; "Jupiter" is the name of its programming and extension model. Each execution is a distinct **invocation** with an independent result. If input #2 fails, inputs #1, #3, #4 still run and report their own status. You use `@ParameterizedTest` *instead of* `@Test`, not in addition to it. The method then declares parameters (e.g. `void check(String input)`) and JUnit injects a value into each parameter per invocation. ## Argument sources `@ParameterizedTest` alone supplies nothing — it needs an **argument source** annotation that provides the data: - `@ValueSource` — a single array of literals (ints, strings, etc.). - `@CsvSource` / `@CsvFileSource` — comma-separated rows, mapped to multiple parameters. - `@MethodSource` — a factory method that returns a `Stream`/`Collection` of arguments. - `@EnumSource` — the constants of an enum. - `@ArgumentsSource` — a custom `ArgumentsProvider` implementation. At least one source is required; you may combine several. ## Dependency These annotations live in the **`junit-jupiter-params`** module (Maven artifact `org.junit.jupiter:junit-jupiter-params`), which is bundled when you depend on the `junit-jupiter` aggregator. A frequent beginner error is having `junit-jupiter-api` but not `-params`, so `@ParameterizedTest` won't resolve. ## Display names Each invocation gets a name from the `name` attribute, a template that can include placeholders like `{index}` and `{arguments}` (e.g. `@ParameterizedTest(name = "[{index}] {0} -> {1}")`). This makes the test report readable. ## Minimal example ```java @ParameterizedTest @ValueSource(strings = {"", "a", "aba"}) void acceptsPalindromes(String s) { assertTrue(isPalindrome(s)); } ``` This runs three times. Each string is its own line in the report. ## Why it matters It encourages **data-driven testing**: you separate the *logic of the test* from the *table of cases*, making it trivial to add a new edge case (one line) and keeping each case independently reported. That improves both coverage and diagnosability.
- Can you put both @Test and @ParameterizedTest on the same method?No. They are mutually exclusive — @ParameterizedTest replaces @Test. Using both is a configuration error; the method will not run as intended.
- What happens if you add @ParameterizedTest but no source annotation?JUnit reports a configuration error / pre-condition violation: a parameterized test requires at least one argument source. It does not silently run once.
Like a cookie cutter (the method) stamped repeatedly over a sheet of dough (each argument set) — same shape, many cookies, and you can see exactly which cookie came out wrong.
saying these in an interview costs you the question
- Thinking @ParameterizedTest runs once like @Test
- Keeping both @Test and @ParameterizedTest on a method
- Forgetting the junit-jupiter-params dependency
- Claiming a loop inside one @Test is equivalent (it stops at the first failed assertion and reports as one test)