Зачем мокировать API?

Мокирование API создаёт имитации реальных API, возвращающие предопределённые ответы. Это необходимо в современной разработке:

Типичные сценарии для мокирования

  1. Недоступность стороннего API — песочница платёжного провайдера упала, но нужно тестировать оплату
  2. API в разработке — бэкенд-команда ещё не закончила endpoint
  3. Снижение затрат — вызов платных API (Google Maps, OpenAI) тысячи раз при тестировании дорог
  4. Детерминированное тестирование — реальные API могут возвращать разные данные; моки — стабильные
  5. Имитация граничных случаев — сложно вызвать 500 от реального API; моки имитируют любой ответ
  6. Тестирование производительности — имитация медленных ответов, таймаутов, сетевых ошибок
  7. Офлайн-разработка — разработчики могут работать без интернета

Stubs vs. Mocks vs. Fakes

ТерминОпределениеПример
StubВозвращает предопределённые ответыВозвращает {id: 1, name: "Alice"} на любой GET /users/1
MockStub + проверяет ожиданияТо же, но проверяет, что запрос был сделан ровно один раз
FakeУпрощённая рабочая реализацияIn-memory БД вместо реальной PostgreSQL

Введение в WireMock

WireMock — самый популярный инструмент мокирования API в экосистеме Java, но работает с любым языком через HTTP API или standalone-сервер.

Запуск WireMock

Standalone:

java -jar wiremock-standalone-3.3.1.jar --port 8080

Docker:

docker run -d -p 8080:8080 wiremock/wiremock:latest

Создание первого Stub

{
  "request": {
    "method": "GET",
    "url": "/api/users/1"
  },
  "response": {
    "status": 200,
    "headers": {"Content-Type": "application/json"},
    "jsonBody": {
      "id": 1,
      "name": "Alice Johnson",
      "email": "alice@example.com"
    }
  }
}

Через HTTP API:

curl -X POST http://localhost:8080/__admin/mappings -d '{
  "request": {"method": "GET", "urlPattern": "/api/users/[0-9]+"},
  "response": {"status": 200, "jsonBody": {"id": 1, "name": "Alice"}}
}'

Request Matching

URL Matching

{"url": "/api/users/1"}                    // Точное совпадение
{"urlPattern": "/api/users/[0-9]+"}        // Regex
{"urlPathPattern": "/api/users/.*"}        // Паттерн пути

Matching заголовков и тела

WireMock поддерживает сложное сопоставление заголовков, query-параметров и тела через JSON paths и regex-паттерны.

Продвинутые возможности WireMock

Имитация задержек

{
  "request": {"method": "GET", "url": "/api/slow"},
  "response": {
    "status": 200,
    "fixedDelayMilliseconds": 3000,
    "jsonBody": {"data": "задержанный ответ"}
  }
}

Имитация ошибок

{
  "request": {"method": "GET", "url": "/api/error"},
  "response": {"status": 500, "jsonBody": {"error": "Internal Server Error"}}
}
{
  "request": {"method": "GET", "url": "/api/timeout"},
  "response": {"fault": "CONNECTION_RESET_BY_PEER"}
}

Stateful-поведение (сценарии)

Разные ответы в зависимости от состояния:

[
  {
    "scenarioName": "Жизненный цикл пользователя",
    "requiredScenarioState": "Started",
    "newScenarioState": "Пользователь создан",
    "request": {"method": "POST", "url": "/api/users"},
    "response": {"status": 201, "jsonBody": {"id": 1, "name": "Alice"}}
  },
  {
    "scenarioName": "Жизненный цикл пользователя",
    "requiredScenarioState": "Пользователь создан",
    "request": {"method": "GET", "url": "/api/users/1"},
    "response": {"status": 200, "jsonBody": {"id": 1, "name": "Alice"}}
  }
]

Верификация запросов

curl http://localhost:8080/__admin/requests/count -d '{
  "method": "POST", "url": "/api/users"
}'
# Ответ: {"count": 1}

Response Templating

Динамические ответы на основе данных запроса с плейсхолдерами.

Стратегии мокирования

Паттерн виртуализации сервисов

Для микросервисов мокируйте внешние зависимости, сохраняя реальные внутренние компоненты.

Мок в CI/CD

services:
  wiremock:
    image: wiremock/wiremock:latest
    ports: ["8080:8080"]
    volumes: ["./tests/mocks:/home/wiremock"]

Альтернативы WireMock

ИнструментЯзыкЛучше всего для
WireMockJava/ЛюбойEnterprise, сложный matching
json-serverNode.jsБыстрый мок из JSON-файла
PrismЛюбойАвто-мок из OpenAPI-спецификации
MSWJavaScriptПерехват запросов в браузере/Node.js
MountebankЛюбойМульти-протокольный (HTTP, TCP, SMTP)

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

  1. Настройте WireMock: Запустите standalone или через Docker. Создайте stub-ы для GET, POST и DELETE.
  2. Request matching: Создайте stub-ы, отвечающие по-разному в зависимости от query-параметров, заголовков и тела.
  3. Имитируйте сбои: Создайте stub-ы для ошибок 500, таймаутов и сбросов соединения.
  4. Верифицируйте запросы: Используйте API верификации, чтобы подтвердить, что клиент сделал ожидаемые запросы.
  5. Stateful-мок: Создайте сценарий, где POST создаёт ресурс, а последующий GET его возвращает.

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

  • Мокирование API имитирует реальное поведение для тестирования, когда API недоступен или непредсказуем
  • WireMock — отраслевой стандарт: поддерживает request matching, templating, задержки, сбои и stateful-сценарии
  • Stub-ы возвращают предопределённые ответы; mock-и добавляют верификацию ожидаемых запросов
  • Используйте мокирование для сторонних API, API в разработке, имитации граничных случаев и CI/CD
  • Response templating и stateful-сценарии обеспечивают реалистичное поведение моков