Skip to main content
skill CX Codex

unit-test-parameterized — Claude Code skill for JUnit 5 tests

A skill that turns one JUnit 5 test method into many runs over different inputs. Useful when you need boundary coverage without copy-pasting assertions.

Install into Claude Code · Skills CLI (Vercel) All methods and platforms ↓
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-parameterized -a claude-code
Open on GitHub

What unit-test-parameterized does

The skill hands your agent ready patterns for parameterized tests in JUnit 5. It covers @ValueSource for plain values, @CsvSource for tabular rows, @MethodSource for complex objects, @EnumSource for enums, and @ArgumentsSource with a custom ArgumentsProvider. Readable output comes from display names like name = "{0}...".

The workflow it describes: put junit-jupiter on the test classpath, pick a data source, make the method parameters match the source types, set a display name, then run ./gradlew test --info or mvn test. Every parameter set executes as its own test invocation, so the report tells you which case broke.

There are sharp edges. The parameter count from the source has to match the method signature or the test will not start. @ValueSource takes primitives, strings and enums only, not objects or null. Strings containing commas need single quotes inside @CsvSource, and a @MethodSource factory method must be static and live in the same test class. Worth checking your current tests against those rules before converting them.

The skill installs into Claude, Codex, Cursor, GitHub Copilot, Gemini CLI and OpenCode.

What it helps with

  • run one check across a dozen input values
  • cover boundary cases such as zero and the maximum
  • keep a table of email addresses and expected results in a single test
  • exercise every enum constant without a method per value
  • move test data into a static factory method

Example prompts for the agent

  • write a JUnit 5 parameterized test for email validation with @CsvSource
  • convert this test to @MethodSource with complex objects
  • add a @ParameterizedTest with int boundary values via @ValueSource

How to install unit-test-parameterized

1Skills CLI (Vercel)

npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-parameterized -a claude-code

2Manually: put the files in place

~/.claude/skills/unit-test-parameterized/SKILL.md

Copy the whole skill folder; for one project use .claude/skills/unit-test-parameterized/

Step by step, with commands for each platform: How to install skills in Claude Code: five ways

Questions about unit-test-parameterized

How do I install unit-test-parameterized in Claude?

Run npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-parameterized -a claude-code. The skill file then sits at ~/.claude/skills/unit-test-parameterized/SKILL.md.

What does unit-test-parameterized do?

It guides the agent through writing parameterized JUnit 5 tests: choosing a data source, matching parameter types, and setting readable display names. One method covers many inputs.

What do I need for it to work?

Parameterized tests need junit-jupiter on the test classpath, which already bundles the params module. The examples use assertj-core for assertions.

Source text

SKILL.md · MIT
---
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:

```xml
<!-- Maven -->
<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <scope>test</scope>
</dependency>
```

```kotlin
// Gradle
testImplementation("org.junit.jupiter:junit-jupiter")
```

### `@ValueSource` — Simple Values

```java
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

```java
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.CsvSource;

@ParameterizedTest
@CsvSource({
  "[email protected], true",
  "[email protected],     true",
  "invalid-email,     false",
  "user@,             false",
  "@example.com,       false"
})
void shouldValidateEmailAddresses(String email, boolean expected) {
  assertThat(UserValidator.isValidEmail(email)).isEqualTo(expected);
}
```

### `@MethodSource` — Complex Data

```java
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

```java
@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

```java
@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`

```java
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

```java
@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

- [JUnit 5 Parameterized Tests](https://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests)
- [`@ParameterizedTest` API](https://junit.org/junit5/docs/current/api/org.junit.jupiter.params/org/junit/jupiter/params/ParameterizedTest.html)

© giuseppe-trisciuoglio · MIT · giuseppe-trisciuoglio/developer-kit

Similar skills

All skills for Testing and QA →

From the same set96

prompt-engineering This skill helps write, debug, and test LLM prompts. Use it for few-shot examples, system prompts, reasoning workflows, and reusable templates. CX Codex +1 3,900installs spring-boot-saga-pattern A skill for distributed transactions in Spring Boot microservices: choreography and orchestration, compensating actions, Kafka, RabbitMQ, Axon. CX Codex +1 3,800installs unit-test-json-serialization A skill with patterns for unit testing JSON serialization and deserialization using Jackson and @JsonTest in Spring Boot. CX Codex +1 3,800installs unit-test-controller-layer Generates isolated MockMvc unit tests for Spring REST controllers with Mockito. Helps verify HTTP status codes, payload validation, and JsonPath assertions. CX Codex +1 3,800installs nextjs-authentication A skill with ready authentication patterns for Next.js 15+ App Router on Auth.js 5: providers, route protection, sessions and roles. CX Codex +1 3,800installs spring-boot-dependency-injection Sets up constructor-first dependency injection patterns for Spring Boot projects. It eliminates field injection and organizes bean selection via @Primary and @Qualifier. CX Codex +1 3,800installs nextjs-code-review Reviews Next.js App Router code before merges, covering component boundaries, Server Actions, caching and routes. Use it after a feature or router migration. CX Codex +1 3,800installs unit-test-wiremock-rest-api A skill with patterns for unit testing external REST APIs through WireMock: stub responses, verify requests, simulate failures with no real network calls. CX Codex +1 3,800installs

Project sponsors

Companies that keep this analytics open
Gold sponsor

Impressions, clicks and code copies — open statistics. We keep the numbers public for the same reason NeBlask itself is public. Become a sponsor