Parametrize JUnit 5 Tests with a Method Source
Drive JUnit 5 parameterised tests from a method source or CSV so edge cases stay explicit and addable without new methods.
Task
Convert repeated assertions into JUnit 5 parameterised tests fed by a method source.
When to use this
A validation function has a dozen hand-written test methods that differ only by input and expected result.
Prerequisites
- Java 17 with JUnit 5
- A function under test with clear inputs and outputs
- A Maven or Gradle build
Steps
1. Feed inputs from a method source.
@ParameterizedTest
@MethodSource("cases")
void validates(String input, boolean expected) {
assertEquals(expected, Validator.isValid(input));
}
static Stream<Arguments> cases() {
return Stream.of(
Arguments.of("ok", true),
Arguments.of("", false),
Arguments.of("bad!", false));
}Expected output: One test method covers every case and each failure names the offending input.
2. Add CSV rows for readability when cases are tabular.
@ParameterizedTest
@CsvSource({"ok,true", "'',false", "bad!,false"})
void validatesCsv(String input, boolean expected) {
assertEquals(expected, Validator.isValid(input));
}Expected output: Tabular cases are editable like data, not code.
Troubleshooting
Problem
Failure output unclear
Solution
Name each case or split sources so the failing argument is visible.
Problem
Tests not discovered
Solution
Ensure the parameterized dependency is present and the source method is static.
Limitations
- Does not suit tests with very different setup per case.
- Argument order mistakes can hide failures.
- Requires readable case names for diagnosis.
What this recipe does
Convert repeated assertions into JUnit 5 parameterised tests fed by a method source.
A validation function has a dozen hand-written test methods that differ only by input and expected result.
Prerequisites
- Java 17 with JUnit 5
- A function under test with clear inputs and outputs
- A Maven or Gradle build
Procedure
- Feed inputs from a method source.
@ParameterizedTest
@MethodSource("cases")
void validates(String input, boolean expected) {
assertEquals(expected, Validator.isValid(input));
}
static Stream<Arguments> cases() {
return Stream.of(
Arguments.of("ok", true),
Arguments.of("", false),
Arguments.of("bad!", false));
}
Expected result: One test method covers every case and each failure names the offending input.
- Add CSV rows for readability when cases are tabular.
@ParameterizedTest
@CsvSource({"ok,true", "'',false", "bad!,false"})
void validatesCsv(String input, boolean expected) {
assertEquals(expected, Validator.isValid(input));
}
Expected result: Tabular cases are editable like data, not code.
How to confirm it worked
Run the commands above and confirm every expected result in order. If a step does not produce the stated output, use the troubleshooting notes before continuing. A passing run shows adding a new case is a one-line data change and failures identify the exact input that broke.
Troubleshooting
Failure output unclear — Name each case or split sources so the failing argument is visible.
Tests not discovered — Ensure the parameterized dependency is present and the source method is static.
Limitations
- Does not suit tests with very different setup per case.
- Argument order mistakes can hide failures.
- Requires readable case names for diagnosis.