Почему важно тестировать обработку ошибок

Когда API работает идеально, тестирование просто. Настоящий вызов — и где прячется большинство багов — в том, как API обрабатывает ситуации, когда что-то идёт не так. Тестирование обработки ошибок проверяет, что API падает корректно, предоставляет полезную информацию и не раскрывает уязвимости.

В продакшне в компаниях вроде Google качество обработки ошибок напрямую влияет на скорость отладки. Чёткое сообщение «Поле ’email’ должно содержать валидный email» экономит часы по сравнению с общим «Bad Request».

Структура ответа об ошибке

Хорошо спроектированный ответ об ошибке следует единообразному формату:

{
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Ошибка валидации запроса",
    "details": [
      {
        "field": "email",
        "message": "Должен быть валидным email-адресом",
        "value": "не-email"
      },
      {
        "field": "age",
        "message": "Должен быть положительным целым числом",
        "value": -5
      }
    ]
  },
  "requestId": "req_abc123",
  "timestamp": "2025-12-15T10:30:00Z"
}

Что проверять в ответах об ошибках

АспектЧто верифицировать
Код статусаСоответствует типу ошибки (400, 401, 403, 404, 422, 500)
Код ошибкиМашиночитаемый, единообразный по всему API
СообщениеЧеловекочитаемое, действенное, без внутренних деталей
ДеталиКонкретные ошибки на уровне полей
ID запросаПрисутствует для отладки
Content-TypeПо-прежнему application/json даже для ошибок

Категории тестирования ошибок

Ошибки валидации ввода (400/422)

Тестируйте каждое поле ввода с невалидными данными:

Отсутствие обязательных полей → "Поле 'name' обязательно"
Неверный тип данных          → "Поле 'age' должно быть целым числом"
Вне диапазона                → "Поле 'age' должно быть от 0 до 150"
Невалидный формат            → "Поле 'email' должно быть валидным"
Слишком длинное              → "Поле 'name' максимум 100 символов"
Невалидный enum              → "Поле 'role': admin, user, viewer"

Ошибки аутентификации (401)

СценарийОжидаемое сообщение
Токен не предоставлен«Требуется аутентификация»
Просроченный токен«Токен истёк»
Некорректный токен«Невалидный токен аутентификации»
Отозванный токен«Токен был отозван»

Ошибки авторизации (403)

СценарийОжидаемое сообщение
Пользователь на admin-endpoint«Недостаточно прав»
Доступ к чужим данным«Доступ запрещён»
Отключённая функция«Недоступно для вашего плана»

Ошибки Not Found (404)

СценарийОжидаемое сообщение
Невалидный ID ресурса«Пользователь не найден»
Удалённый ресурс«Ресурс больше не существует»
Неверный endpointСтандартный ответ 404

Продвинутое тестирование ошибок

Единообразие ошибок

Проверьте, что ошибки следуют одному формату по всему API:

  • Одинаковая JSON-структура для всех ответов
  • Единообразные коды ошибок
  • Единообразное использование кодов статуса

Безопасность в сообщениях об ошибках

Проверьте, что сообщения НЕ раскрывают:

  • Имена таблиц или колонок БД
  • Stack trace или пути файлов
  • SQL-запросы
  • Имена внутренних сервисов или IP-адреса
  • Факт существования пользователя (для endpoint-ов логина)

Плохо: "Error: SELECT * FROM users WHERE id=42 failed: connection to postgres:5432 refused"

Хорошо: "Не удалось обработать запрос. Попробуйте позже. Ссылка: req_abc123"

Обработка ошибок под нагрузкой

  • БД недоступна? (должен быть 503, не 500 со stack trace)
  • Некорректный JSON? (должен быть 400, не 500)
  • Огромный payload? (должен быть 413 Payload Too Large)
  • Неподдерживаемый Content-Type? (должен быть 415)

Интернационализация сообщений об ошибках

Если API поддерживает несколько языков:

  • Сообщения на каждом языке через Accept-Language
  • Fallback на язык по умолчанию
  • Коды ошибок неизменны вне зависимости от языка

Построение набора тестов ошибок

Для каждого endpoint-а создайте матрицу:

POST /api/users
├── Отсутствует 'name'    → 400, VALIDATION_ERROR
├── Пустой 'name'         → 400, VALIDATION_ERROR
├── Имя слишком длинное   → 400, VALIDATION_ERROR
├── Невалидный email      → 422, VALIDATION_ERROR
├── Дублирующийся email   → 409, CONFLICT
├── Без auth-токена       → 401, AUTH_REQUIRED
├── Невалидный токен      → 401, INVALID_TOKEN
├── Роль user на admin    → 403, FORBIDDEN
├── Некорректный JSON     → 400, PARSE_ERROR
└── Неверный Content-Type → 415, UNSUPPORTED_MEDIA_TYPE

Практическое упражнение

  1. Отобразите ответы об ошибках: Отправьте 10 невалидных запросов к JSONPlaceholder и задокументируйте каждый формат ответа
  2. Проверьте единообразие: Сравните форматы ошибок между endpoint-ами
  3. Аудит безопасности: Поищите ответы, раскрывающие внутренние детали
  4. Создайте матрицу ошибок: Для endpoint-а регистрации перечислите все сценарии ошибок

Ключевые выводы

  • Тестирование обработки ошибок так же важно, как тестирование позитивных сценариев
  • Ответы об ошибках должны следовать единой структуре: код статуса, код ошибки, сообщение и детали
  • Никогда не раскрывайте внутренние детали в сообщениях об ошибках
  • Тестируйте каждое поле с каждым типом невалидных данных
  • Стройте систематические матрицы тестов ошибок для каждого endpoint-а