PluginBench
Skill
Review
Audit score 70

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
Prerequisites
  • JUnit 5 (junit-jupiter) on test classpath
  • AssertJ or similar assertion library (optional but recommended)
  • Gradle or Maven build tool
Claude Code
Cursor
Windsurf
Cline

How to use unit-test-parameterized

  1. 1.Ensure junit-jupiter dependency is added to your test classpath
  2. 2.Choose appropriate data source: @ValueSource for simple values, @CsvSource for tabular data, @MethodSource for complex objects
  3. 3.Write test method with @ParameterizedTest annotation and matching parameters for your data source
  4. 4.Add custom display name using name parameter for readable test output
  5. 5.Run tests with ./gradlew test --info or mvn test to verify all parameter combinations execute

Use cases

Good for
  • 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
Who it's for
  • 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

What's the difference between @ValueSource and @CsvSource?

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

Can I use @ValueSource with null values?

No, @ValueSource does not support null directly. Use @MethodSource or @ArgumentsSource instead to include null test cases.

How do I test with complex objects?

Use @MethodSource with a static factory method that returns Stream<Arguments>, allowing you to construct and pass complex objects as test parameters.

What does the name parameter do?

The name parameter in @ParameterizedTest customizes test output labels. Use placeholders like {0}, {1} to reference parameters, making test results more readable.

Do I need to write separate test methods for each parameter set?

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

  1. Add dependency: Ensure junit-jupiter-params is on test classpath (included in junit-jupiter)
  2. Choose source: @ValueSource for simple values, @CsvSource for tabular data, @MethodSource for complex objects
  3. Match parameters: Test method parameters must match data source types
  4. Set display names: Use name = "{0}..." for readable output
  5. Validate: Run ./gradlew test --info or mvn test and 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 @MethodSource for complex objects, @CsvSource for 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
  • @ValueSource limitation: Only supports primitives, strings, and enums — not objects or null directly
  • CSV escaping: Strings with commas must use single quotes in @CsvSource
  • @MethodSource visibility: 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