toolsmockingapicontract-testingtesting

Мок-серверы для QA: WireMock и компания — когда подменять зависимость заглушкой

В прошлый раз мы говорили про Testcontainers — как поднять реальные зависимости в тесте. Сегодня обратная сторона: когда зависимость реально поднять нельзя или не нужно — её подменяют мок-сервером. Это HTTP-заглушка, которая отвечает так, как вы запрограммировали: нужный статус, тело, задержку, ошибку.

Главное — понимать, когда мок уместен, что он должен уметь и где он врёт.

Зачем мокать

  • Чужой / платный API: платёжки, карты, SMS, погода — дёргать реальный дорого, лимитировано или просто нельзя в CI.
  • Нестабильная зависимость: сторонний сервис падает/тормозит — тесты не должны от этого флакать.
  • Сервиса ещё нет: фронт/QA работают параллельно с бэком по согласованному контракту.
  • Трудные ответы: 429, 503, таймаут, битое тело, частичный ответ — в реале не воспроизвести по требованию, а в моке — одной настройкой.

Что должен уметь хороший мок-сервер

  • Матчинг запроса: стаб срабатывает по методу, пути, заголовкам, query, телу (точное/по шаблону/regex).
  • Fault injection: задержки, коды ошибок, обрыв соединения, мусорное тело — для проверки устойчивости клиента.
  • Stateful-сценарии: ответ меняется по шагам (создал → теперь существует), эмуляция состояний.
  • Record & replay: записать реальный трафик и проигрывать как мок (стартовый набор стабов из прода).
  • Verify: проверить, что клиент действительно сделал ожидаемый вызов (с нужным телом/заголовками).
  • Templating: динамический ответ на основе запроса (echo id, текущее время).

Инструменты и их ниши

  • WireMock — мощный (JVM, есть standalone/Docker): богатый матчинг, fault injection, proxy+record, verify. Рабочая лошадка для интеграционных тестов.
  • MockServer — гибкие expectations, проксирование, на JVM; близкий конкурент WireMock.
  • Mockoon — десктоп-GUI, мгновенный старт без кода; удобно для ручного QA и быстрых стабов.
  • Prism — мок прямо из OpenAPI-спеки: заглушка автоматически соответствует контракту (и валидирует запросы по нему).
  • Hoverfly — лёгкий proxy с record/replay (capture/simulate), хорош для снятия реального трафика.

Мок или реальная зависимость (Testcontainers)?

Простое правило:

  • Реально (Testcontainers) — то, что ваше и поднимается локально: БД, брокер, кэш, ваш же сервис. Мок тут только спрячет реальные баги интеграции.
  • Мок — внешнее и неподконтрольное: чужие/платные API, сервисы за границей сети, то, чего ещё нет, и редкие сбойные ответы.

Не мокайте то, что можно поднять по-настоящему. Мок своей же БД — это тест заглушки, а не системы.

Главный риск мока — контрактный дрейф

Заглушка застывает: реальный API поменял формат/коды, а ваш мок всё ещё отвечает по-старому. Тесты зелёные, прод падает. Как страховаться:

  • Contract testing (Pact): провайдер и потребитель проверяют согласованность контракта автоматически.
  • Мок из спеки: Prism генерит заглушку из OpenAPI — она не разойдётся со схемой, пока схема актуальна.
  • Периодический smoke против реального API (в отдельном прогоне, не в каждом PR).
  • Record-from-real: пересоздавать стабы из свежего реального трафика.

Мок как инструмент тестирования устойчивости

Самая недооценённая польза: моком тривиально воспроизвести то, что в реале не вызвать по кнопке.

  • Таймаут и медленный ответ → проверяем клиентские таймауты и ретраи.
  • 429/503 → проверяем backoff, circuit breaker, грациозную деградацию.
  • Битое/частичное тело → парсинг не падает, ошибка обрабатывается.
  • Обрыв соединения посреди ответа → клиент не зависает.

Частые ошибки

  • Мок слишком розовый: всегда 200, никаких ошибок — клиент не протестирован на сбои.
  • Мокают то, что можно поднять реально (своя БД/сервис).
  • Нет verify: тест зелёный, даже если клиент вообще не сделал вызов.
  • Стабы устарели и разошлись с реальным API (контрактный дрейф).
  • Только happy-path, без 4xx/5xx/таймаутов.
  • Хардкод портов/хостов вместо конфигурируемого base URL.

Чек-лист по мокам (10 пунктов)

  1. Мокается только внешнее/неподконтрольное; своё — поднимается реально.
  2. Матчинг запроса достаточно строгий (метод/путь/тело/заголовки).
  3. Есть негативные стабы: 4xx, 5xx, таймаут, битое тело.
  4. verify проверяет, что клиент сделал ожидаемый вызов.
  5. Контракт под защитой: Pact / мок из OpenAPI / запись из реального.
  6. Есть периодический smoke против реального API.
  7. Stateful-сценарии там, где ответ зависит от предыдущих шагов.
  8. Base URL зависимости конфигурируем (легко переключить мок/реал).
  9. Стабы версионируются вместе с тестами.
  10. Используется fault injection для проверки устойчивости клиента.

Итог

Мок-сервер — это про контроль: вы задаёте ровно те ответы, которые нужны, включая сбойные. Но именно поэтому мок легко делает тесты слишком зелёными и расходится с реальностью. Мокайте внешнее, держите контракт под защитой (Pact/OpenAPI/реальный smoke), обязательно тестируйте ошибки и проверяйте вызовы через verify. Реальную инфру — через Testcontainers, а не заглушкой.

Источники