Agent Skills by ALSEL
Anthropic Claudeソフトウェア開発⭐ リポ 0品質スコア 50/100

unit-test-exception-handler

Spring Bootアプリケーションにおける`@ExceptionHandler`および`@ControllerAdvice`のユニットテストパターンを提供します。エラーレスポンスのフォーマット検証、例外のモック、HTTPステータスコードの確認、フィールドレベルのバリデーションエラーテスト、カスタムエラーペイロードのアサーションに対応します。Spring例外ハンドラーのテスト、REST APIエラーテスト、またはController Adviceのモックを記述する際に活用してください。

description の原文を見る

Provides patterns for unit testing `@ExceptionHandler` and `@ControllerAdvice` in Spring Boot applications. Validates error response formatting, mocks exceptions, verifies HTTP status codes, tests field-level validation errors, and asserts custom error payloads. Use when writing Spring exception handler tests, REST API error tests, or mocking controller advice.

SKILL.md 本文

ExceptionHandler と ControllerAdvice のユニットテスト

概要

このスキルは Spring Boot 例外ハンドラのユニットテストを書くためのパターンを提供します。MockMvc を使用した @ControllerAdvice クラス内の @ExceptionHandler メソッドのテスト、HTTP ステータスのアサーション、JSON レスポンス検証、フィールドレベルの検証エラーテスト、およびハンドラ依存関係のモック化に対応します。

使用する場合

  • @ExceptionHandler メソッドのユニットテストを書く場合
  • @ControllerAdvice グローバル例外処理をテストする場合
  • REST API エラーレスポンスのフォーマットを検証する場合
  • コントローラテストで例外をモック化する場合
  • フィールドレベルの検証エラーレスポンスをテストする場合
  • カスタムエラーペイロードと HTTP ステータスコードをアサートする場合

手順

  1. テストコントローラを作成 して各 @ExceptionHandler をトリガーする特定の例外をスロー
  2. ControllerAdvice を登録 - MockMvcBuilders.standaloneSetup() 上で setControllerAdvice() を使用
  3. HTTP ステータスコードをアサート - .andExpect(status().isXxx()) で確認
  4. エラーレスポンスフィールドを検証 - jsonPath("$.field") マッチャーを使用
  5. 検証エラーをテスト - 無効なペイロードを送信して MethodArgumentNotValidException がフィールドレベルの詳細を生成することを確認
  6. 失敗をデバッグ - .andDo(print()) を使用 — ハンドラが呼び出されない場合は setControllerAdvice() が呼ばれていること、例外タイプがマッチしていることを確認

例外ハンドラとエラー DTO

@ControllerAdvice
public class GlobalExceptionHandler {

  @ExceptionHandler(ResourceNotFoundException.class)
  @ResponseStatus(HttpStatus.NOT_FOUND)
  public ErrorResponse handleNotFound(ResourceNotFoundException ex) {
    return new ErrorResponse(404, "Not Found", ex.getMessage());
  }

  @ExceptionHandler(ValidationException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ErrorResponse handleValidation(ValidationException ex) {
    return new ErrorResponse(400, "Bad Request", ex.getMessage());
  }

  @ExceptionHandler(MethodArgumentNotValidException.class)
  @ResponseStatus(HttpStatus.BAD_REQUEST)
  public ValidationErrorResponse handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
    Map<String, String> errors = new HashMap<>();
    ex.getBindingResult().getFieldErrors().forEach(e -> errors.put(e.getField(), e.getDefaultMessage()));
    return new ValidationErrorResponse(400, "Validation Failed", errors);
  }
}

public record ErrorResponse(int status, String error, String message) {}
public record ValidationErrorResponse(int status, String error, Map<String, String> errors) {}

ユニットテスト

@ExtendWith(MockitoExtension.class)
class GlobalExceptionHandlerTest {

  private MockMvc mockMvc;

  @BeforeEach
  void setUp() {
    GlobalExceptionHandler handler = new GlobalExceptionHandler();
    mockMvc = MockMvcBuilders.standaloneSetup(new TestController())
        .setControllerAdvice(handler)
        .build();
  }

  @Test
  void shouldReturn404WhenResourceNotFound() throws Exception {
    mockMvc.perform(get("/api/users/999"))
        .andExpect(status().isNotFound())
        .andExpect(jsonPath("$.status").value(404))
        .andExpect(jsonPath("$.error").value("Not Found"))
        .andExpect(jsonPath("$.message").value("User not found"));
  }

  @Test
  void shouldReturn400WithFieldErrorsOnValidationFailure() throws Exception {
    mockMvc.perform(post("/api/users")
        .contentType("application/json")
        .content("{\"name\":\"\",\"email\":\"invalid\"}"))
        .andExpect(status().isBadRequest())
        .andExpect(jsonPath("$.status").value(400))
        .andExpect(jsonPath("$.errors.name").value("must not be blank"))
        .andExpect(jsonPath("$.errors.email").value("must be a valid email"));
  }
}

@RestController
@RequestMapping("/api")
class TestController {
  @GetMapping("/users/{id}") public User getUser(@PathVariable Long id) {
    throw new ResourceNotFoundException("User not found");
  }
  @PostMapping("/users") public User createUser(@RequestBody @Valid User user) {
    throw new ValidationException("Validation failed");
  }
}

ベストプラクティス

  • @ExceptionHandler メソッドを独立してテスト - 特定の例外をスロー
  • setControllerAdvice() を使用して正確に 1 つの @ControllerAdvice インスタンスを登録 — スキップしないこと
  • HTTP ステータスだけでなく、エラーレスポンス本体のすべてのフィールドをアサート
  • 検証エラーについては、フィールド名キーとエラーメッセージの値の両方を検証
  • MockMvcBuilders.standaloneSetup() を使用 - 完全な Spring コンテキストなしで、隔離されたハンドラテストの場合
  • アサーション失敗をログに記録 - .andDo(print()) をチェーンして、テスト失敗時に要求/レスポンスを出力

よくある落とし穴

  • ハンドラが呼び出されない: ビルダー上で setControllerAdvice() が呼ばれていることを確認
  • JsonPath 不一致: .andDo(print()) を使用して、実際のレスポンス構造を検査
  • ステータスが 200: ハンドラメソッドに @ResponseStatus がないか、ResponseEntity を返していない
  • ハンドラの重複: @Order が優先度を制御します;より具体的な例外タイプが優先される
  • ハンドラロジックをテスト: 外部依存関係をモック化し、レスポンス変換のみをテスト

制約と警告

  • @ExceptionHandler の具体性: より具体的な例外タイプがまず最初にマッチされます;Exception.class はマッチしないすべてのタイプをキャッチ
  • @ResponseStatus のデフォルト: @ResponseStatus または ResponseEntity を返さない場合、HTTP ステータスはデフォルトで 200
  • グローバル vs ローカルスコープ: @ControllerAdvice 内の @ExceptionHandler はグローバル;コントローラで宣言された場合、そのコントローラのみにローカル
  • ロギング副作用: ハンドラがログを記録する場合、verify(mockLogger).logXxx(...) で検証する必要があります
  • ローカライゼーション: MessageSource を使用する場合、異なる Locale 値でテストしてメッセージ解決を確認
  • セキュリティコンテキスト: AuthorizationException ハンドラは SecurityContextHolder にアクセス可能 — コンテキストが正しく評価されることをテスト

ライセンス: MIT(寛容ライセンスのため全文を引用しています) · 原本リポジトリ

詳細情報

作者
giuseppe-trisciuoglio
リポジトリ
giuseppe-trisciuoglio/developer-kit
ライセンス
MIT
最終更新
不明

Source: https://github.com/giuseppe-trisciuoglio/developer-kit / ライセンス: MIT

関連スキル

汎用ソフトウェア開発⭐ リポ 39,967

doubt-driven-development

重要な判断はすべて、本番環境への展開前に新しい視点から対抗的レビューを実施します。速度より正確性が重要な場合、不慣れなコードを扱う場合、本番環境・セキュリティに関わるロジック・取り消し不可の操作など影響度が高い場合、または後でバグを修正するよりも今検証する方が効率的な場合に活用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 1,175

apprun-skills

TypeScriptを使用したAppRunアプリケーションのMVU設計に関する総合的なガイダンスが得られます。コンポーネントパターン、イベントハンドリング、状態管理(非同期ジェネレータを含む)、パラメータと保護機能を備えたルーティング・ナビゲーション、vistestを使用したテストに対応しています。AppRunコンポーネントの設計・レビュー、ルートの配線、状態フローの管理、AppRunテストの作成時に活用してください。

by yysun
OpenAIソフトウェア開発⭐ リポ 797

desloppify

コードベースのヘルスチェックと技術負債の追跡ツールです。コード品質、技術負債、デッドコード、大規模ファイル、ゴッドクラス、重複関数、コードスメル、命名規則の問題、インポートサイクル、結合度の問題についてユーザーが質問した場合に使用してください。また、ヘルススコアの確認、次の改善項目の提案、クリーンアップ計画の作成をリクエストされた際にも対応します。29言語に対応しています。

by Git-on-my-level
汎用ソフトウェア開発⭐ リポ 39,967

debugging-and-error-recovery

テストが失敗したり、ビルドが壊れたり、動作が期待と異なったり、予期しないエラーが発生したりした場合に、体系的な根本原因デバッグをガイドします。推測ではなく、根本原因を見つけて修正するための体系的なアプローチが必要な場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

test-driven-development

テスト駆動開発により実装を進めます。ロジックの実装、バグの修正、動作の変更など、あらゆる場面で活用できます。コードが正常に動作することを証明する必要がある場合、バグ報告を受けた場合、既存機能を修正する予定がある場合に使用してください。

by addyosmani
汎用ソフトウェア開発⭐ リポ 39,967

incremental-implementation

変更を段階的に実施します。複数のファイルに影響する機能や変更を実装する場合に使用してください。大量のコードを一度に書こうとしている場合や、タスクが一度では完結できないほど大きい場合に活用します。

by addyosmani
本サイトは GitHub 上で公開されているオープンソースの SKILL.md ファイルをクロール・インデックス化したものです。 各スキルの著作権は原作者に帰属します。掲載に問題がある場合は info@alsel.co.jp または /takedown フォームよりご連絡ください。
原作者: giuseppe-trisciuoglio · giuseppe-trisciuoglio/developer-kit · ライセンス: MIT