mcpField
U
unit-test-service-layer

unit-test-service-layer

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

unit-test-service-layer について

MockitoでJavaのサービス層をテストする開発者向けの実践ガイドです。依存関係のモック化、呼び出し検証、例外ケースを含む、`@Service` クラスの独立したテスト方法を扱います。

主な機能

  1. 01MockitoExtensionによるテスト設定
  2. 02リポジトリとクライアントのモック化
  3. 03結果と依存先呼び出しの検証
  4. 04例外とエッジケースのテスト
  5. 05テスト実行とカバレッジ確認

活用シーン

  1. 01@Serviceのビジネスロジックを単独でテスト
  2. 02サービスからリポジトリへの呼び出しを確認
  3. 03外部APIの失敗処理をテスト

インストール

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

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

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

同梱ファイルreferences/examples.md

詳細

Mockito を使用したサービス層の単体テスト

概要

Mockito を使用して @Service クラスを単体テストするためのパターンを紹介します。リポジトリー呼び出しをモックし、メソッドの呼び出しを検証し、例外のシナリオをテストして、外部 API のレスポンスをスタブ化します。Spring コンテナーやデータベースを使わずに、高速で分離されたテストを実行できます。

使用する場面

  • @Service クラスのビジネスロジックをテストする
  • リポジトリーや外部クライアントの依存関係をモックする
  • モック化したコラボレーターとのサービスのやり取りを検証する
  • サービスのエラー処理やエッジケースをテストする
  • 高速で分離された単体テストを作成する(データベースや API 呼び出しは不要)

手順

検証チェックポイントを含む、Mockito を使用したサービス層のテストでは、次のワークフローに従ってください。

1. テストクラスをセットアップする

@ExtendWith(MockitoExtension.class) を使用して、Mockito のアノテーションを有効にします。

2. @Mock と @InjectMocks でモックを宣言する

依存関係(リポジトリー、クライアント)には @Mock を使用し、テスト対象のサービスには @InjectMocks を使用します。

3. 検証を含む Arrange-Act-Assert

Arrange:テストデータを作成し、when().thenReturn() を使用してモックの戻り値を設定します。

Act:テスト対象のサービスメソッドを実行します。

Assert:

  • AssertJ のアサーションで戻り値を検証します
  • verify() でモックとのやり取りを検証します
  • 検証チェックポイント:テストを実行し、成功することを確認します
4. 例外のシナリオをテストする

when().thenThrow() を使用して、モックが例外をスローするように設定します。

検証チェックポイント:例外の型とメッセージを確認します

5. 網羅性を確認する
  • テストスイート全体を実行します:mvn test または gradle test
  • カバレッジレポートを確認します:mvn test jacoco:report
  • 検証チェックポイント:すべてのサービスメソッドに対応するテストがあることを確認します

例

基本的なサービスのテストパターン
@ExtendWith(MockitoExtension.class)
class UserServiceTest {

  @Mock
  private UserRepository userRepository;

  @InjectMocks
  private UserService userService;

  @Test
  void shouldReturnUserWhenFound() {
    // Arrange
    User expected = new User(1L, "Alice");
    when(userRepository.findById(1L)).thenReturn(Optional.of(expected));

    // Act
    User result = userService.getUser(1L);

    // Assert
    assertThat(result.getName()).isEqualTo("Alice");
    verify(userRepository).findById(1L);
  }

  @Test
  void shouldThrowWhenUserNotFound() {
    // Arrange
    when(userRepository.findById(999L)).thenReturn(Optional.empty());

    // Act & Assert
    assertThatThrownBy(() -> userService.getUser(999L))
      .isInstanceOf(UserNotFoundException.class);
  }
}
メソッド呼び出しを検証する
@Test
void shouldSendEmailOnUserCreation() {
  User newUser = new User(1L, "Alice", "[email protected]");
  when(userRepository.save(any(User.class))).thenReturn(newUser);

  enrichmentService.registerNewUser("Alice", "[email protected]");

  verify(userRepository).save(any(User.class));
  verify(emailService).sendWelcomeEmail("[email protected]");
}

複数の依存関係、引数キャプター、非同期サービス、InOrder による検証など、その他のパターンについては、references/examples.md を参照してください。

ベストプラクティス

  • JUnit 5 との統合には @ExtendWith(MockitoExtension.class) を使用する
  • テスト対象のサービスが直接依存するものだけをモックする
  • 適切な連携を確認するために やり取りを検証する
  • テストメソッドごとに 1 つの動作をテストする - テストの焦点を絞ります
  • わかりやすい変数名を使用する:expectedUser、actualUser、captor
  • 値オブジェクトや DTO には 実際のインスタンスを作成する(モック化しないでください)

制約と注意事項

  • 値オブジェクトや DTO はモック化せず、テストデータを使って実際のインスタンスを作成してください。
  • 依存関係を過剰にモック化しないでください。サービスにコラボレーターが多すぎる場合は、リファクタリングを検討してください。
  • テストは独立している必要があります。実行順序に依存しないでください。
  • @Spy の使用には注意してください。部分的なモック化は理解や保守がより難しくなります。
  • private メソッドを直接テストせず、public メソッドの動作を通じてテストしてください。
  • 引数マッチャー(any()、eq())は、同じスタブ内で実際の値と混在させることはできません。
  • 過剰な検証は避け、テストシナリオで重要なやり取りのみを検証してください。

参考資料

コメント