mcpField
U
unit-test-parameterized

unit-test-parameterized

github.com/giuseppe-trisciuoglioテスト・品質3653.8k 回インストール7 週間前に更新
リポジトリ

unit-test-parameterized について

Java 開発者向けに、JUnit 5 のパラメーター化テストを扱うスキルです。単純値、表形式データ、複雑なオブジェクト、列挙型のデータソースに加え、表示名や検証方法も説明します。

主な機能

  1. 016 種類の JUnit 5 データソースのパターン
  2. 02読みやすいテスト表示名の設定
  3. 03データソースとメソッド引数の型合わせ
  4. 04境界値とシナリオのテスト手法
  5. 05テスト実行と依存関係の確認

活用シーン

  1. 01複数の入力パターンのテスト
  2. 02Java の境界値の確認
  3. 03重複するテストロジックの集約
  4. 04列挙型やオブジェクトのシナリオ検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/giuseppe-trisciuoglio/developer-kit --skill unit-test-parameterized

インストール後、Claude Code で/unit-test-parameterizedを入力して読み込まれたか確認します。

詳細

JUnit 5 によるパラメーター化ユニットテスト

概要

JUnit 5 を使用した Java のパラメーター化ユニットテストのパターンを紹介します。@ValueSource、@CsvSource、@MethodSource、@EnumSource、@ArgumentsSource、カスタム表示名について説明します。同じテストロジックを複数の入力値で実行することで、テストの重複を減らします。

使用する場面

  • 複数の入力の組み合わせを扱う JUnit テストを作成する場合
  • Java でデータ駆動テストを実装する場合
  • 同じテストを異なる値で実行する場合(境界値分析)
  • 1 つのテストメソッドから複数のシナリオをテストする場合

手順

  1. 依存関係を追加する:junit-jupiter-params がテストクラスパスに含まれていることを確認します(junit-jupiter に含まれています)。
  2. ソースを選択する:単純な値には @ValueSource、表形式のデータには @CsvSource、複雑なオブジェクトには @MethodSource を使用します。
  3. パラメーターを一致させる:テストメソッドのパラメーターは、データソースの型と一致させる必要があります。
  4. 表示名を設定する:読みやすい出力にするには、name = "{0}..." を使用します。
  5. 検証する:./gradlew test --info または mvn test を実行し、すべてのパラメーターの組み合わせが実行されることを確認します。

例

Maven / Gradle の依存関係

JUnit 5 のパラメーター化テストには junit-jupiter が必要です(params が含まれています)。アサーション用に assertj-core を追加します。


<dependency>
  <groupId>org.junit.jupiter</groupId>
  <artifactId>junit-jupiter</artifactId>
  <scope>test</scope>
</dependency>
// Gradle
testImplementation("org.junit.jupiter:junit-jupiter")
@ValueSource — 単純な値
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 — 表形式のデータ
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 — 複雑なデータ
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 の値
@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);
}
カスタム表示名
@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));
}
カスタム 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);
}
エラー条件のテスト
@ParameterizedTest
@ValueSource(strings = {"", " ", null})
void shouldThrowExceptionForInvalidInput(String input) {
  assertThatThrownBy(() -> Parser.parse(input))
    .isInstanceOf(IllegalArgumentException.class);
}

ベストプラクティス

  • 説明的な表示名を使用します。読みやすい出力にするには、name = "{0}..." を指定します。
  • 境界値をテストします。最小値、最大値、ゼロ、エッジケースを含めます。
  • テストロジックを絞り込みます。パラメーターセットごとにアサーションを 1 つにします。
  • 複雑なオブジェクトには @MethodSource、表形式のデータには @CsvSource を使用します。
  • テストデータを論理的に整理します。関連するシナリオをまとめます。

制約と警告

  • パラメーター数を一致させる必要があります:ソースから渡されるパラメーター数は、テストメソッドのシグネチャと一致する必要があります。
  • @ValueSource の制限:プリミティブ型、文字列、Enum のみをサポートします。オブジェクトや null は直接指定できません。
  • CSV のエスケープ:カンマを含む文字列は、@CsvSource でシングルクォートを使用する必要があります。
  • @MethodSource の可視性:ファクトリーメソッドは、同じテストクラス内で static にする必要があります。
  • 表示名のプレースホルダー:パラメーターを参照するには、{0}、{1} などを使用します。
  • 実行回数:各パラメーターセットは、個別のテスト呼び出しとして実行されます。

参考資料

コメント