unit-test-parameterized
giuseppe-trisciuoglio/developer-kit
Data-driven unit tests with JUnit 5 @ParameterizedTest, @ValueSource, @CsvSource, @MethodSource.
What is unit-test-parameterized?
Provides parameterized testing patterns for Java using JUnit 5. Reduces test duplication by running the same test logic with multiple input values, supporting simple values, tabular data, complex objects, and enums. Use when writing data-driven tests, testing multiple scenarios from a single method, or performing boundary value analysis.
- Generate parameterized tests using @ParameterizedTest with @ValueSource, @CsvSource, @MethodSource, @EnumSource, and @ArgumentsSource
- Run the same test logic with multiple input combinations in a single test method
- Create readable test output with custom display names using name parameter
- Test boundary values and edge cases efficiently without duplicating test code
- Support complex test data through custom ArgumentsProvider implementations
How to install unit-test-parameterized
npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-parameterized- JUnit 5 (junit-jupiter) on test classpath
- AssertJ or similar assertion library (optional but recommended)
- Gradle or Maven build tool
How to use unit-test-parameterized
- 1.Ensure junit-jupiter dependency is added to your test classpath
- 2.Choose appropriate data source: @ValueSource for simple values, @CsvSource for tabular data, @MethodSource for complex objects
- 3.Write test method with @ParameterizedTest annotation and matching parameters for your data source
- 4.Add custom display name using name parameter for readable test output
- 5.Run tests with ./gradlew test --info or mvn test to verify all parameter combinations execute
Use cases
- Testing email validation with multiple valid and invalid formats using @CsvSource
- Running arithmetic operations across boundary values (MIN_VALUE, 0, MAX_VALUE) with @ValueSource
- Testing enum handling by iterating all enum values with @EnumSource
- Validating range checks with complex objects and multiple parameters via @MethodSource
- Testing error conditions with null and empty string inputs
- Java developers writing unit tests with JUnit 5
- QA engineers implementing data-driven test scenarios
- Teams practicing boundary value analysis and comprehensive test coverage
- Developers reducing test code duplication across similar test cases
unit-test-parameterized FAQ
@ValueSource is for simple single values (primitives, strings, enums) and creates one parameter per test invocation. @CsvSource is for tabular data with multiple columns, allowing you to test multiple parameters per invocation.
No, @ValueSource does not support null directly. Use @MethodSource or @ArgumentsSource instead to include null test cases.
Use @MethodSource with a static factory method that returns Stream<Arguments>, allowing you to construct and pass complex objects as test parameters.
The name parameter in @ParameterizedTest customizes test output labels. Use placeholders like {0}, {1} to reference parameters, making test results more readable.
No, parameterized tests run all parameter combinations in a single test method, eliminating code duplication and making tests more maintainable.
Full instructions (SKILL.md)
Source of truth, from giuseppe-trisciuoglio/developer-kit.
name: unit-test-parameterized description: Provides parameterized testing patterns with JUnit 5, generates data-driven unit tests using @ParameterizedTest, @ValueSource, @CsvSource, @MethodSource. Creates tests that run the same logic with multiple input values. Use when writing data-driven Java tests, multiple test cases from single method, or boundary value analysis. allowed-tools: Read, Write, Bash, Glob, Grep
Parameterized Unit Tests with JUnit 5
Overview
Provides patterns for parameterized unit tests in Java using JUnit 5. Covers @ValueSource, @CsvSource, @MethodSource, @EnumSource, @ArgumentsSource, and custom display names. Reduces test duplication by running the same test logic with multiple input values.
When to Use
- Writing JUnit tests with multiple input combinations
- Implementing data-driven tests in Java
- Running same test with different values (boundary analysis)
- Testing multiple scenarios from single test method
Instructions
- Add dependency: Ensure
junit-jupiter-paramsis on test classpath (included injunit-jupiter) - Choose source:
@ValueSourcefor simple values,@CsvSourcefor tabular data,@MethodSourcefor complex objects - Match parameters: Test method parameters must match data source types
- Set display names: Use
name = "{0}..."for readable output - Validate: Run
./gradlew test --infoormvn testand verify all parameter combinations execute
Examples
Maven / Gradle Dependency
JUnit 5 parameterized tests require junit-jupiter (includes params). Add assertj-core for assertions:
<!-- Maven -->
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
// Gradle
testImplementation("org.junit.jupiter:junit-jupiter")
@ValueSource — Simple Values
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import static org.assertj.core.api.Assertions.*;
@ParameterizedTest
@ValueSource(strings = {"hello", "world", "test"})
void shouldCapitalizeAllStrings(String input) {
assertThat(StringUtils.capitalize(input)).isNotEmpty();
}
@ParameterizedTest
@ValueSource(ints = {1, 2, 3, 4, 5})
void shouldBePositive(int number) {
assertThat(number).isPositive();
}
@ParameterizedTest
@ValueSource(ints = {Integer.MIN_VALUE, -1, 0, 1, Integer.MAX_VALUE})
void shouldHandleBoundaryValues(int value) {
assertThat(Math.incrementExact(value)).isGreaterThan(value);
}
@CsvSource — Tabular Data
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;
@ParameterizedTest
@CsvSource({
"alice@example.com, true",
"bob@gmail.com, true",
"invalid-email, false",
"user@, false",
"@example.com, false"
})
void shouldValidateEmailAddresses(String email, boolean expected) {
assertThat(UserValidator.isValidEmail(email)).isEqualTo(expected);
}
@MethodSource — Complex Data
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import java.util.stream.Stream;
@ParameterizedTest
@MethodSource("additionTestCases")
void shouldAddNumbersCorrectly(int a, int b, int expected) {
assertThat(Calculator.add(a, b)).isEqualTo(expected);
}
static Stream<Arguments> additionTestCases() {
return Stream.of(
Arguments.of(1, 2, 3),
Arguments.of(0, 0, 0),
Arguments.of(-1, 1, 0),
Arguments.of(100, 200, 300)
);
}
@EnumSource — Enum Values
@ParameterizedTest
@EnumSource(Status.class)
void shouldHandleAllStatuses(Status status) {
assertThat(status).isNotNull();
}
@ParameterizedTest
@EnumSource(value = Status.class, names = {"ACTIVE", "INACTIVE"})
void shouldHandleSpecificStatuses(Status status) {
assertThat(status).isIn(Status.ACTIVE, Status.INACTIVE);
}
Custom Display Names
@ParameterizedTest(name = "Discount of {0}% should be calculated correctly")
@ValueSource(ints = {5, 10, 15, 20})
void shouldApplyDiscount(int discountPercent) {
double result = DiscountCalculator.apply(100.0, discountPercent);
assertThat(result).isEqualTo(100.0 * (1 - discountPercent / 100.0));
}
Custom ArgumentsProvider
class RangeValidatorProvider implements ArgumentsProvider {
@Override
public Stream<? extends Arguments> provideArguments(ExtensionContext context) {
return Stream.of(
Arguments.of(0, 0, 100, true),
Arguments.of(50, 0, 100, true),
Arguments.of(-1, 0, 100, false),
Arguments.of(101, 0, 100, false)
);
}
}
@ParameterizedTest
@ArgumentsSource(RangeValidatorProvider.class)
void shouldValidateRange(int value, int min, int max, boolean expected) {
assertThat(RangeValidator.isInRange(value, min, max)).isEqualTo(expected);
}
Error Condition Testing
@ParameterizedTest
@ValueSource(strings = {"", " ", null})
void shouldThrowExceptionForInvalidInput(String input) {
assertThatThrownBy(() -> Parser.parse(input))
.isInstanceOf(IllegalArgumentException.class);
}
Best Practices
- Use descriptive display names:
name = "{0}..."for readable output - Test boundary values: include min, max, zero, and edge cases
- Keep test logic focused: single assertion per parameter set
- Use
@MethodSourcefor complex objects,@CsvSourcefor tabular data - Organize test data logically — group related scenarios together
Constraints and Warnings
- Parameter count must match: Number of parameters from source must match test method signature
@ValueSourcelimitation: Only supports primitives, strings, and enums — not objects or null directly- CSV escaping: Strings with commas must use single quotes in
@CsvSource @MethodSourcevisibility: Factory methods must be static in the same test class- Display name placeholders: Use
{0},{1}, etc. to reference parameters - Execution count: Each parameter set runs as a separate test invocation
References
Related skills
More from giuseppe-trisciuoglio/developer-kit and the wider catalog.

unit-test-scheduled-async
Unit test Spring @Scheduled and @Async methods with JUnit 5, Awaitility, and Mockito without waiting for real scheduling intervals.

unit-test-security-authorization
Unit test Spring Security authorization with @PreAuthorize, @Secured, and role-based access control patterns.

unit-test-service-layer
Unit test service layer with Mockito: mock dependencies, verify interactions, test business logic in isolation.

unit-test-utility-methods
Test patterns for utility classes, static methods, and pure functions with edge case coverage.

unit-test-wiremock-rest-api
Unit test REST API integrations with WireMock stubs, request verification, and error simulation.

wiremock-standalone-docker
Provides patterns and configurations for running WireMock as a standalone Docker container. Generates mock HTTP endpoints, creates stub mappings for testing, validates integration scenarios, and simulates error conditions. Use when you need to mock APIs, create a mock server, stub external services, simulate third-party APIs, or fake API responses for integration testing.