mcpField
U
unit-test-utility-methods

unit-test-utility-methods

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

unit-test-utility-methods について

ユーティリティクラス、静的ヘルパー、純粋関数の単体テストを作成する開発者向けスキルです。不要なモックを避け、境界や端のケースを重視します。

主な機能

  1. 01静的ヘルパーと純粋関数のテスト
  2. 02nullおよび空入力の確認
  3. 03境界条件の検証
  4. 04パラメータ化テストの活用
  5. 05純粋なユーティリティでのモック回避

活用シーン

  1. 01文字列の整形と変換のテスト
  2. 02計算と変換の検証
  3. 03検証処理やコレクション補助の確認

インストール

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

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

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

同梱ファイルreferences/edge-cases.mdreferences/parameterized-tests.md

詳細

ユーティリティクラスと静的メソッドのユニットテスト

概要

このスキルは、静的ヘルパーメソッドや純粋関数を持つユーティリティクラスのテストを生成します。null の処理、エッジケース、境界条件、および文字列操作、計算、データ検証、コレクションなどの一般的なユーティリティをテストするためのパターンを提供します。純粋関数にはモックは必要ありません。

使用する場面

次の場合にこのスキルを使用します。

  • 静的メソッドを持つユーティリティ/ヘルパークラスのテストを書く場合
  • 状態や副作用のない純粋関数をテストする場合
  • 文字列操作、書式設定、変換ユーティリティをテストする場合
  • 計算、変換、数学のヘルパー関数をテストする場合
  • データ検証やフォーマッターユーティリティをテストする場合
  • ユーティリティコードでの null/空入力の処理を検証する場合
  • コレクションや配列のヘルパーメソッドをテストする場合

手順

  1. テストクラスを作成する:ユーティリティの名前に基づいて命名します(例:StringUtilsTest)
  2. 正常系をテストする:有効な入力と期待される出力を確認します
  3. エッジケースをテストする:null、空、空白、単一要素を確認します
  4. 境界条件をテストする:最大/最小値、大きな数値、精度を確認します
  5. 説明的な名前を使用する:test1 ではなく shouldCapitalizeFirstLetter を使用します
  6. AssertJ を使用する:読みやすく、メソッドを連結できるアサーションにします
  7. @ParameterizedTest を使用する:類似した複数の入力には使用します(references/parameterized-tests.md を参照)
  8. モックを避ける:純粋なユーティリティにモックは不要です

例

基本的な静的ユーティリティのテスト
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;

class StringUtilsTest {

    @Test
    void shouldCapitalizeFirstLetter() {
        assertThat(StringUtils.capitalize("hello")).isEqualTo("Hello");
    }

    @Test
    void shouldReturnNullForNullInput() {
        assertThat(StringUtils.capitalize(null)).isNull();
    }

    @Test
    void shouldHandleEmptyString() {
        assertThat(StringUtils.capitalize("")).isEmpty();
    }

    @Test
    void shouldHandleSingleCharacter() {
        assertThat(StringUtils.capitalize("a")).isEqualTo("A");
    }
}
包括的な例:isEmpty の実装
// Input: public static boolean isEmpty(String str)
//   { return str == null || str.trim().isEmpty(); }

class StringUtilsTest {

    @Test
    void shouldReturnTrueForNullString() {
        assertThat(StringUtils.isEmpty(null)).isTrue();
    }

    @Test
    void shouldReturnTrueForEmptyString() {
        assertThat(StringUtils.isEmpty("")).isTrue();
    }

    @Test
    void shouldReturnTrueForWhitespaceOnly() {
        assertThat(StringUtils.isEmpty("   ")).isTrue();
    }

    @Test
    void shouldReturnFalseForNonEmptyString() {
        assertThat(StringUtils.isEmpty("hello")).isFalse();
    }
}
null 安全なユーティリティ
class NullSafeUtilsTest {

    @Test
    void shouldReturnDefaultWhenNull() {
        assertThat(NullSafeUtils.getOrDefault(null, "default")).isEqualTo("default");
    }

    @Test
    void shouldReturnValueWhenNotNull() {
        assertThat(NullSafeUtils.getOrDefault("value", "default")).isEqualTo("value");
    }

    @Test
    void shouldReturnFalseWhenBlank() {
        assertThat(NullSafeUtils.isNotBlank(null)).isFalse();
        assertThat(NullSafeUtils.isNotBlank("   ")).isFalse();
    }
}
数学/計算ユーティリティ
class MathUtilsTest {

    @Test
    void shouldCalculatePercentage() {
        assertThat(MathUtils.percentage(25, 100)).isEqualTo(25.0);
    }

    @Test
    void shouldHandleZeroDivisor() {
        assertThat(MathUtils.percentage(50, 0)).isZero();
    }

    @Test
    void shouldRoundToDecimalPlaces() {
        assertThat(MathUtils.round(3.14159, 2)).isEqualTo(3.14);
    }

    @Test
    void shouldHandleFloatingPointWithTolerance() {
        assertThat(MathUtils.multiply(0.1, 0.2))
            .isCloseTo(0.02, within(0.0001));
    }
}
コレクションユーティリティ
class CollectionUtilsTest {

    @Test
    void shouldFilterList() {
        List<Integer> result = CollectionUtils.filter(List.of(1, 2, 3, 4), n -> n % 2 == 0);
        assertThat(result).containsExactly(2, 4);
    }

    @Test
    void shouldHandleNullList() {
        assertThat(CollectionUtils.filter(null, n -> true)).isEmpty();
    }

    @Test
    void shouldJoinWithSeparator() {
        assertThat(CollectionUtils.join(List.of("a", "b", "c"), "-")).isEqualTo("a-b-c");
    }

    @Test
    void shouldDeduplicateList() {
        assertThat(CollectionUtils.deduplicate(List.of("a", "b", "a")))
            .containsExactlyInAnyOrder("a", "b");
    }
}
データ検証ユーティリティ
class ValidatorUtilsTest {

    @Test
    void shouldValidateEmailFormat() {
        assertThat(ValidatorUtils.isValidEmail("[email protected]")).isTrue();
        assertThat(ValidatorUtils.isValidEmail("invalid")).isFalse();
    }

    @Test
    void shouldValidateUrlFormat() {
        assertThat(ValidatorUtils.isValidUrl("https://example.com")).isTrue();
        assertThat(ValidatorUtils.isValidUrl("not a url")).isFalse();
    }

    @Test
    void shouldValidateCreditCard() {
        assertThat(ValidatorUtils.isValidCreditCard("4532015112830366")).isTrue();
        assertThat(ValidatorUtils.isValidCreditCard("1234567890123456")).isFalse();
    }
}
Clock 依存のあるユーティリティ(まれなケース)
@ExtendWith(MockitoExtension.class)
class DateUtilsTest {

    @Mock
    private Clock clock;

    @Test
    void shouldGetDateFromClock() {
        when(clock.instant()).thenReturn(Instant.parse("2024-01-15T10:00:00Z"));
        assertThat(DateUtils.today(clock)).isEqualTo(LocalDate.of(2024, 1, 15));
    }
}

ベストプラクティス

  • 純粋関数のみをテストする - 副作用や状態への依存がないことを確認します
  • 正常系とエッジケースを網羅する - null、空、空白、極端な値を確認します
  • 説明的なテスト名を使用する - shouldReturnNullWhenInputIsNull
  • 類似した複数の入力には @ParameterizedTest を使用する(references/parameterized-tests.md を参照)
  • 境界条件をテストする - 最小/最大値、オーバーフロー、精度を確認します
  • 純粋関数のモックは避ける - Clock などの外部依存関係のみをモックします
  • テストを独立させる - テスト間に実行順序への依存がないようにします

制約と注意事項

  • 静的メソッドはモックしない:やむを得ない場合に限り、リフレクションユーティリティを使用します
  • 純粋関数の要件:状態を持つユーティリティはテストが難しくなるため、不変性を優先します
  • 浮動小数点数の精度:完全一致は使用せず、isCloseTo(delta) を使用します
  • null 処理の一貫性:ユーティリティが null を返すか例外をスローするかを決め、それに応じてテストします
  • スレッドセーフ:静的ユーティリティはスレッドセーフである必要があります。並行動作は個別に検証します
  • 不変の入力:ユーティリティが入力パラメーターを変更するかどうかを文書化します
  • エッジケースのリファレンス:境界値テストのパターンについては references/edge-cases.md を参照してください

コメント