К основному содержанию
скилл CX Codex

unit-test-exception-handler — скилл для Claude Code: тесты

Паттерны юнит-тестов для @ExceptionHandler и @ControllerAdvice в Spring Boot: проверка кодов ответа, JSON и ошибок валидации по полям.

Установить в Claude Code · Через Skills CLI (Vercel) Все способы и платформы ↓
npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-exception-handler -a claude-code
Открыть на GitHub

Что делает unit-test-exception-handler

Скилл описывает, как писать тесты на обработчики исключений Spring Boot. Внутри — готовые примеры: класс @ControllerAdvice с методами на ResourceNotFoundException, ValidationException и MethodArgumentNotValidException, DTO для ответа об ошибке и тестовый контроллер, который эти исключения бросает.

Схема работы простая. Тестовый контроллер намеренно бросает нужное исключение, MockMvcBuilders.standaloneSetup() собирает MockMvc, а setControllerAdvice() подключает ваш обработчик. Дальше проверяете статус через status().isNotFound(), поля ответа через jsonPath("$.status") и текст ошибок валидации по каждому полю. Полный контекст Spring поднимать не нужно.

Если тест падает, а обработчик будто не вызвался — почти всегда забыт setControllerAdvice() или тип исключения не совпал. Ещё частая причина: статус 200 вместо 404, потому что на методе нет @ResponseStatus. Для отладки цепляйте .andDo(print()) и смотрите фактическую структуру ответа. Скилл советует проверять все поля тела ответа, а не только код.

Из ограничений: более конкретные типы исключений перехватываются раньше, а Exception.class ловит всё остальное, поэтому порядок и @Order стоит держать в голове. Обработчики с логированием проверяются через verify(mockLogger), а при использовании MessageSource тесты прогоняют с разными Locale.

Какие задачи решает

  • проверить, что обработчик отдаёт 404 на отсутствующий ресурс
  • убедиться, что ошибки валидации приходят по каждому полю
  • собрать MockMvc без поднятия полного контекста Spring
  • найти причину, почему @ExceptionHandler не срабатывает в тесте
  • проверить логирование внутри обработчика исключения

Примеры запросов агенту

  • напиши юнит-тест на @ControllerAdvice для ResourceNotFoundException
  • проверь через MockMvc, что невалидный email даёт 400 и ошибку по полю email
  • добавь .andDo(print()) в падающий тест обработчика и покажи ответ

Как установить unit-test-exception-handler

1Через Skills CLI (Vercel)

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

2Вручную: положить файлы

~/.claude/skills/unit-test-exception-handler/SKILL.md

Папка скилла целиком; для одного проекта — .claude/skills/unit-test-exception-handler/

По шагам, с командами для каждой платформы: Как установить скилл в Claude Code: пять способов

Вопросы о unit-test-exception-handler

Как установить unit-test-exception-handler в Claude?

Через npx skills add giuseppe-trisciuoglio/developer-kit --skill unit-test-exception-handler -a claude-code. Файл скилла окажется в ~/.claude/skills/unit-test-exception-handler/SKILL.md.

Что делает этот скилл?

Даёт паттерны юнит-тестов для @ExceptionHandler и @ControllerAdvice: проверку HTTP-статусов, полей JSON-ответа, ошибок валидации по полям и мокирование зависимостей обработчика.

Нужен ли полный контекст Spring для таких тестов?

Нет. Скилл строит MockMvc через MockMvcBuilders.standaloneSetup() и подключает обработчик методом setControllerAdvice().

Исходный текст

SKILL.md · MIT
---
name: unit-test-exception-handler
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.
allowed-tools: Read, Write, Bash, Glob, Grep
---

# Unit Testing ExceptionHandler and ControllerAdvice

## Overview

This skill provides patterns for writing unit tests for Spring Boot exception handlers. It covers testing `@ExceptionHandler` methods in `@ControllerAdvice` classes using MockMvc, including HTTP status assertions, JSON response validation, field-level validation error testing, and mocking handler dependencies.

## When to Use

- Writing unit tests for `@ExceptionHandler` methods
- Testing `@ControllerAdvice` global exception handling
- Validating REST API error response formatting
- Mocking exceptions in controller tests
- Testing field-level validation error responses
- Asserting custom error payloads and HTTP status codes

## Instructions

1. **Create a test controller** that throws specific exceptions to trigger each `@ExceptionHandler`
2. **Register ControllerAdvice** via `setControllerAdvice()` on `MockMvcBuilders.standaloneSetup()`
3. **Assert HTTP status codes** with `.andExpect(status().isXxx())`
4. **Verify error response fields** using `jsonPath("$.field")` matchers
5. **Test validation errors** by sending invalid payloads and checking `MethodArgumentNotValidException` produces field-level details
6. **Debug failures** with `.andDo(print())` — if handler not invoked, verify `setControllerAdvice()` is called and exception type matches

## Examples

### Exception Handler and Error DTO

```java
@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) {}
```

### Unit Test

```java
@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");
  }
}
```

## Best Practices

- Test each `@ExceptionHandler` method independently with a dedicated exception throw
- Register exactly one `@ControllerAdvice` instance via `setControllerAdvice()` — never skip it
- Assert all fields in the error response body, not just the HTTP status
- For validation errors, verify both the field name key and the error message value
- Use `MockMvcBuilders.standaloneSetup()` for isolated handler tests without full Spring context
- Log assertion failures: chain `.andDo(print())` to print request/response when a test fails

## Common Pitfalls

- Handler not invoked: ensure `setControllerAdvice()` is called on the builder
- JsonPath mismatch: use `.andDo(print())` to inspect actual response structure
- Status is 200: missing `@ResponseStatus` on the handler method
- Duplicate handlers: `@Order` controls precedence; more specific exception types take priority
- Testing handler logic instead of behavior: mock external dependencies, test only the response transformation

## Constraints and Warnings

- **`@ExceptionHandler` specificity**: more specific exception types are matched first; `Exception.class` catches all unmatched types
- **`@ResponseStatus` default**: without `@ResponseStatus` or returning `ResponseEntity`, HTTP status defaults to 200
- **Global vs local scope**: `@ExceptionHandler` in `@ControllerAdvice` is global; declared in a controller it is local only to that controller
- **Logging side effects**: handlers that log should be verified with `verify(mockLogger).logXxx(...)`
- **Localization**: when using `MessageSource`, test with different `Locale` values to confirm message resolution
- **Security context**: `AuthorizationException` handlers can access `SecurityContextHolder` — test that context is correctly evaluated

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

Похожие скиллы

Всё по теме «Тесты и QA» →
321-frameworks-spring-boot-testing-unit-tests Juan Antonio Breña Moral Скилл ведёт агента по юнит-тестам Spring Boot: Mockito без поднятия контекста, срезы для контроллеров, параметризованные тесты. Пригодится, когда в проекте расплодились @SpringBootTest. CX Codex +1 387установок 131-java-testing-unit-testing Juan Antonio Breña Moral Скилл помогает писать и рефакторить модульные тесты на Java по стандартам JUnit 5, AssertJ и Mockito. Он находит антипаттерны вроде общего состояния и проверяет граничные условия. CX Codex +1 449установок Python Unit Test Generator — Comprehensive, Coverage-Mapped & Production-Ready sivasaiyadav8143 Промпт превращает кусок Python-кода в готовый набор юнит-тестов на pytest с картой покрытия и моками внешних зависимостей. GP ChatGPT ★ 174 597звёзд репо springboot-tdd affaan-m Скилл задаёт TDD-процесс для Spring Boot: тесты сначала, затем код, рефакторинг и проверка покрытия. Пригодится для фич, багфиксов и API. CX Codex +1 4 700установок typescript-unit-testing bmad-labs Скилл для юнит-тестов TypeScript и NestJS: Jest, моки через @golevelup/ts-jest и структура AAA. Пригодится, когда пишете или чините .spec.ts. CX Codex +1 496установок java-springboot официальный github Задаёт практики разработки Spring Boot-приложений: от структуры проекта до тестов и безопасности. Пригодится, когда Copilot пишет или проверяет Java-код. 21 272установок

Из того же набора93

unit-test-caching Паттерны юнит-тестов для аннотаций Spring Cache: проверка попаданий в кэш, вытеснения и ключей SpEL без поднятия полного контекста Spring. CX Codex +1 3 700установок langchain4j-ai-services-patterns Скилл показывает, как собирать декларативные AI Services на LangChain4j: интерфейсы, аннотации, память и вызов инструментов. CX Codex +1 3 700установок qdrant Скилл даёт шаблоны интеграции векторной базы Qdrant в Java и Spring Boot через LangChain4j. Помогает настроить семантический поиск и хранилище эмбеддингов для RAG. CX Codex +1 3 700установок unit-test-mapper-converter Скилл для юнит-тестов MapStruct-мапперов и конвертеров: проверяет маппинг полей, null, вложенные объекты и обратное преобразование. CX Codex +1 3 700установок rag Скилл помогает развернуть пайплайн Retrieval-Augmented Generation: от нарезки документов и расчёта эмбеддингов до поиска в векторной базе и передачи контекста модели. CX Codex +1 3 700установок unit-test-scheduled-async Скилл с готовыми шаблонами юнит-тестов для Spring-методов @Scheduled и @Async: JUnit 5, CompletableFuture, Awaitility, Mockito. CX Codex +1 3 700установок unit-test-utility-methods Скилл пишет юнит-тесты для утилитных классов и статических методов: проверяет null, пустые строки, границы и точность. CX Codex +1 3 700установок nextjs-data-fetching Скилл даёт готовые паттерны выборки данных в Next.js App Router: от серверных компонентов и ISR до интеграции с SWR и React Query. CX Codex +1 3 700установок

Спонсоры проекта

Компании, которые помогают держать аналитику открытой