skip to content

@ParameterizedTest

@ParameterizedTest runs one test body across many inputs, fed by @ValueSource, @CsvSource, @MethodSource or @EnumSource. Interviewers ask about it when discussing table-driven testing and boundary-value coverage.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

6

What is @ParameterizedTest in JUnit 5, and how does it differ from a plain @Test?

level: juniorimportance: must knowfreq 70%

answer

  1. Template method run once per argument set
  2. Replaces @Test, needs a source annotation
  3. Independent invocation + report line per input
  4. Lives in junit-jupiter-params
  5. 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 lines
java
import 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

for a junior

Knows it runs the method once per input and must be paired with a source like @ValueSource instead of @Test.

for a middle

Explains the independent-invocation/report-per-input benefit, names the common sources, and knows it lives in junit-jupiter-params.

for a senior

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).

for a principal

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)

context

open as a page

What is @MethodSource, when is it the right choice, and what are the rules for the factory method it points to?

level: middleimportance: must knowfreq 58%

basics

~20 s

@MethodSource names a method that returns the test data, usually a Stream of Arguments. Use it when the inputs are real objects or computed at runtime — things you can't write as plain literals in @ValueSource or @CsvSource.

open as a page

Compare @ValueSource and @CsvSource. When would you choose each, and how do they map to test method parameters?

level: middleimportance: must knowfreq 62%

basics

~10 s

@ValueSource gives a single column of values to a one-parameter method. @CsvSource gives comma-separated rows, so each row maps to several parameters. Use @ValueSource for one input; use @CsvSource when you need input-plus-expected pairs.

open as a page

How do @EnumSource and the @ParameterizedTest name template work, including filtering enum constants and customizing display names?

level: middleimportance: should knowfreq 40%

basics

~20 s

@EnumSource runs the test once per constant of an enum, injecting each constant. You can include or exclude specific names with its mode/names attributes. The name attribute on @ParameterizedTest sets each invocation's display label using placeholders like {index} and {0}.

open as a page

Explain implicit and explicit argument conversion in @ParameterizedTest, and when you would use @ConvertWith or aggregate arguments with @AggregateWith / ArgumentsAccessor.

level: seniorimportance: should knowfreq 30%

basics

~20 s

JUnit automatically converts string source values (like from @CsvSource) into the parameter's type — that's implicit conversion. When the built-in rules can't do it, you supply a converter with @ConvertWith. To bundle many columns into one object, you use an ArgumentsAccessor or a custom aggregator via @AggregateWith.

open as a page

What is @ArgumentsSource, and how do you design a custom ArgumentsProvider (and a composed annotation) for reusable parameterized-test data?

level: principalimportance: nice to knowfreq 18%

basics

~20 s

@ArgumentsSource points a parameterized test at a class you write that implements ArgumentsProvider and produces the argument sets in code. It is the most flexible, reusable source — you can even wrap it in your own custom annotation so tests just say @MyData.

open as a page