GH GambleHub

Mocking и stubs для интеграций

1) Зачем нужны моки и заглушки

Интеграции с платежными провайдерами, KYC-сервисами, брокерами сообщений, CRM и т. п. делают тесты медленными, нестабильными и дорогими. Моки/заглушки позволяют:
  • изолировать логику сервиса от нестабильного окружения;
  • детерминировать ответы и ошибки;
  • воспроизводить редкие граничные кейсы (таймауты, 429/5xx, неконсистентность);
  • запускать тесты локально и в CI быстро и предсказуемо.
💡 Принцип: чем ниже уровень теста (Unit/Component), тем больше замещаем; чем ближе к прод-реальности (Integration/E2E), тем меньше заглушек.

2) Термины и таксономия

Stub — простая заглушка с фиксированным ответом, без проверок взаимодействий.
Mock — объект, который ожидает вызовы и верифицирует их (порядок/количество/аргументы).
Fake — упрощенная реализация (например, In-Memory репозиторий) с реальным поведением.
Spy — обертка, записывающая фактические вызовы.
Service Virtualization — «виртуальный» внешний сервис с сценариями, состоянием и сетевыми особенностями.
Record/Replay — запись реального трафика и последующее воспроизведение (с фильтрами/редакцией).

Когда что выбирать:
СитуацияИнструмент
Чистая бизнес-логикаFakes (in-memory), unit-mocks
HTTP-интеграция с простыми кейсамиStubs (WireMock/MockServer/HTTPServer)
Проверка контракта клиента к провайдеруCDC mocks (Pact)
Сложные сценарии/состояния/ошибки сетиService virtualization / Hoverfly / MockServer
Сообщения (Kafka/RabbitMQ)Testcontainers + schema-aware продьюсер/консьюмер stubs

3) Архитектурные паттерны для тестируемости

Ports & Adapters (Hexagonal): выносите интеграцию за интерфейсы — легко подменить на fake/mock.
Антикоррупционный слой (ACL): один модуль переводит внешнюю модель в доменную — меньше точек мока.
Contract-aware клиенты: генерация по OpenAPI/Protobuf → меньше ручных несоответствий.
Feature-флаги и sandbox-режимы: безопасные ключи/эндпоинты для стаба провайдера.

4) HTTP: инструменты и примеры

4.1 WireMock (standalone/Java DSL)

JSON-стаб:
json
{
"request": { "method": "POST", "urlPath": "/v1/payouts", "headers": { "Idempotency-Key": { "matches": ".+" } } },
"response": {
"status": 201,
"headers": { "Content-Type": "application/json" },
"jsonBody": { "id": "po_123", "status": "queued" },
"fixedDelayMilliseconds": 80
}
}
Java DSL (с проверкой тела и вариациями):
java stubFor(post(urlEqualTo("/v1/payouts"))
.withHeader("Idempotency-Key", matching(".+"))
.withRequestBody(matchingJsonPath("$.amount", equalTo("100. 00")))
.willReturn(aResponse(). withStatus(201). withHeader("Content-Type","application/json")
.withBody("{\"id\":\"po_123\",\"status\":\"queued\"}")));

4.2 MockServer (динамика/верификации)

json
{
"httpRequest": { "method": "GET", "path": "/v1/wallets/w123" },
"httpResponse": { "statusCode": 200, "headers":[{"name":"Content-Type","values":["application/json"]}],
"body": { "id":"w123","currency":"EUR","balance":0 } }
}

4.3 Hoverfly (middleware, record/replay)

Запишите трафик против «песочницы» провайдера, очистите PII, зафиксируйте как fixture.
В режиме simulate добавьте вариации: 200/4xx/5xx, задержки и «flaky» окна.

4.4 Node (Nock) / Python (responses) / Go (`httptest`)

Nock:
js nock('https://psp. example. com')
.post('/v1/payouts'). reply(201, { id:'po_123', status:'queued' })
.post('/v1/payouts'). reply (409, {code: 'duplicate'}) ;//second call - conflict
Go:
go srv:= httptest. NewServer(http. HandlerFunc(func(w http. ResponseWriter, r http. Request){
if r. Header. Get("Idempotency-Key") == "" { w. WriteHeader(400); return }
w. Header(). Set("Content-Type","application/json")
w. WriteHeader(201); w. Write([]byte(`{"id":"po_123","status":"queued"}`))
}))
defer srv. Close()

5) gRPC/Protobuf

5.1 Генерация стаба

Сгенерируйте сервер по `.proto`, реализуйте методы с контролируемыми ответами.
Проверяйте метаданные (headers), статусы (`codes.InvalidArgument`, `codes.DeadlineExceeded`).

Go gRPC fake (фрагмент):
go type FakePayouts struct{ pb. UnimplementedPayoutsServer }
func (f FakePayouts) Create(ctx context. Context, in pb. PayoutReq)(pb. PayoutRes,error){
if in. Amount <= 0 { return nil, status. Error(codes. InvalidArgument,"amount>0") }
return &pb. PayoutRes{Id:"po_123", Status:"QUEUED"}, nil
}

5.2 grpcurl для негативов


grpcurl -plaintext -d '{"amount":0}' localhost:50051 payouts. Payouts/Create

6) Сообщения и стримы: Kafka/RabbitMQ

6.1 Schema-aware моки

Используйте Schema Registry и валидируйте Avro/JSON-Schema/Protobuf в тестах.
Producer-тест: сообщение соответствует схеме; Consumer-тест: принимает старую и новую версии.

6.2 Testcontainers (пример Kafka + Registry)

java
KafkaContainer kafka = new KafkaContainer(DockerImageName. parse("confluentinc/cp-kafka:7. 6. 1"));
kafka. start();
//We publish the event and wait for consumption with deduplication by key

6.3 Негативы

Дубликаты, перестановка порядка, задержка доставки, «ядовитые» сообщения (dead-letter).
Большие сообщения (near-limit), нераспознанные версии схем.

7) Contract-aware заглушки

7.1 Pact (CDC mocks)

Consumer формирует ожидания → pact-файл → provider верифицирует на стенде.
Pact stub server воспроизводит ожидания для интеграционных тестов клиента.

7.2 OpenAPI/Protobuf → генерация стабов

Инструменты, которые поднимают мок-сервер из спецификации (в т. ч. Prism, openapi-mock, grpc-mock).
Включайте негативные примеры/коды в спецификацию: это тоже контракт.

8) Сеть и хаос: симуляция отказов

Задержки и джиттер: фиксированные/распределенные; проверяйте дедлайны и пер-try timeout.
Таймауты/разрывы: half-open соединения, RST, reset потока H2, 503/Retry-After.
Пакетные потери/дубликаты: для gRPC/стримов.
Инструменты: Toxiproxy, MockServer (fault injection), xk6-disruptor, netem в CI.

Пример Toxiproxy (CLI):

toxiproxy-cli toxic add psp --type latency --latency 300 --jitter 100

9) Данные, секреты и детерминизм

Redact и синтетика: никакого PII в фикстурах; деньги — decimal/строгое форматирование.
Фиксация времени: fake clock; «вчера/сегодня» — контролируйте.
Идемпотентность: один и тот же `Idempotency-Key` → тот же ответ.
Генераторы: фабрики/билдеры данных с прозрачными значениями (e.g., `test_user_001`).
Версионируйте фикстуры (теги), не храните «снятые» ответы без медиации.

10) CI/CD и окружения

Матрица: unit (in-process fakes) → component (локальная виртуализация) → integration (минимум моков, Testcontainers).
Артефакты: pact-файлы, OpenAPI-снапшоты, логи мок-серверов, PCAP при падениях.
Параллельность: уникальные порты/префиксы ключей; изоляция контейнеров.
Gate: контракт зеленый (CDC verify), спецификация валидна (lint), негативы пройдены.

11) Антипаттерны

Моки «копируют» дефекты реального сервиса → ложная уверенность. Лечится контрактами и периодическим record/verify.
«Макромоки» целого мира в каждом тесте → хрупкость, дорогой мейнтенанс. Делайте тонкие порты и ACL.
Моки в E2E, где нужна реальная интеграция (особенно платежи/вебхуки с HMAC/mTLS).
Флейки из-за времени/рандома/сетевых гонок → используйте fake clock, детерминированные сиды.
Секреты в фикстурах/репозитории. Секреты — только через секрет-хранилище CI.

12) Специфика iGaming/финансов

Платежи/выводы: моки должны поддерживать `Idempotency-Key`, `Retry-After`, HMAC/mTLS, санкционные коды и «долгие» ответы.
Бонус-логика/антифрод: сценарии velocity/429, ATO/челлендж, риск-решения `allow/deny/challenge` с TTL.
KYC/AML: sandbox-ответы по уровням KYC, негативы (mismatch, недействительные документы), вебхуки с anti-replay (`X-Timestamp` окно).
Юрисдикции/тенанты: обязательные заголовки `X-Tenant/X-Region`, разные профили ответов.

13) Мини-рецепты (шпаргалка)

Повтор платежа: WireMock «Scenarios» — первый `201`, второй `409 duplicate`.
Медленный PSP: MockServer `responseDelay` + проверка пер-try timeout в клиенте.
Webhooks: локальный HTTP сервер + проверка подписи HMAC; повтор через 5 сек не создает дубль.
Kafka-дубликаты: публикуйте одно и то же сообщение дважды; хендлер обязан быть идемпотентным.
gRPC-статусы: matrix тестов по `codes` (InvalidArgument, DeadlineExceeded, ResourceExhausted).

14) Чек-лист prod-готовности

  • Порты/адаптеры выделены; интеграции скрыты за интерфейсами.
  • Для HTTP/gRPC — есть contract-aware стабы (Pact/OpenAPI/Proto) с негативами.
  • Для брокеров — Testcontainers + Registry; тесты дубликатов/порядка/больших сообщений.
  • Хаос: задержки, таймауты, reset, 429/503 с `Retry-After`; сеть эмулируется (Toxiproxy/netem).
  • Фикстуры без PII; fake clock; идемпотентность чекится.
  • Матрица CI: unit → component → integration; артефакты логов/контрактов сохраняются.
  • Песочницы провайдеров: ключи отделены, эндпоинты сконфигурированы, есть runbook.
  • Record/Replay обновляется по расписанию, трасы редактируются.
  • Метрики flaky и длительности тестов под контролем; алерты при росте.

15) TL;DR

Изолируйте интеграции через тонкие порты и используйте правильный инструмент под задачу: stubs для простых кейсов, mocks для верификации взаимодействий, fakes для реалистичного поведения, service virtualization и chaos — для сетевых и редких ошибок. Делайте моки контракт-осознанными (Pact/OpenAPI/Proto), держите фикстуры детерминированными и без PII, симулируйте задержки/таймауты/429/5xx. В CI стройте пирамиду: unit → component → integration; релиз блокируйте при красных контрактах. Для платежных/KYC-путей учитывайте HMAC/mTLS, идемпотентность и негативные сценарии.

Contact

Свяжитесь с нами

Обращайтесь по любым вопросам или за поддержкой.Мы всегда готовы помочь!

Начать интеграцию

Email — обязателен. Telegram или WhatsApp — по желанию.

Ваше имя необязательно
Email необязательно
Тема необязательно
Сообщение необязательно
Telegram необязательно
@
Если укажете Telegram — мы ответим и там, в дополнение к Email.
WhatsApp необязательно
Формат: +код страны и номер (например, +380XXXXXXXXX).

Нажимая кнопку, вы соглашаетесь на обработку данных.