Mocking and stubs for integrations
1) Why do we need midges and plugs
Integrations with payment providers, KYC services, message brokers, CRM, etc. make tests slow, unstable and expensive. Moki/plugs allow:- Isolate service logic from an unstable environment
- Determine responses and errors
- reproduce rare border cases (timeouts, 429/5xx, inconsistency);
- run tests locally and in CI quickly and predictably.
2) Terms and taxonomy
Stub is a simple stub with a fixed response, without interaction checks.
Mock - an object that waits for calls and verifies them (order/number/arguments).
Fake is a simplified implementation (for example, an In-Memory repository) with real behavior.
Spy is a wrapper that records actual calls.
Service Virtualization is a "virtual" external service with scripts, status and network features.
Record/Replay - recording of real traffic and subsequent playback (with filters/edition).
3) Architectural patterns for testability
Ports & Adapters (Hexagonal): take the integration beyond the interfaces - it is easy to replace it with fake/mock.
Anti-corruption layer (ACL): one module translates an external model into a domain model - fewer moka points.
Contract-aware clients: OpenAPI/Protobuf generation → fewer manual inconsistencies.
Feature flags and sandbox modes: secure keys/endpoints for the provider's stable.
4) HTTP: tools and examples
4. 1 WireMock (standalone/Java DSL)
JSON stab: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 (with body check and variations):
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 (Dynamics/Verifications)
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)
Record the traffic against the provider's sandbox, clear the PII, fix it as fixture.
In simulate mode, add variations: 200/4xx/5xx, delays and "flaky" windows.
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 Stab generation
Generate a server by '.proto', implement methods with controlled responses.
Check metadata (headers), statuses ('codes. InvalidArgument`, `codes. DeadlineExceeded`).
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 for negatives
grpcurl -plaintext -d '{"amount":0}' localhost:50051 payouts. Payouts/Create
6) Posts and streams: Kafka/RabbitMQ
6. 1 Schema-aware moki
Use Schema Registry and validate Avro/JSON-Schema/Protobuf in tests.
Producer test: the message corresponds to the schema; Consumer test: accepts old and new versions.
6. 2 Testcontainers (Kafka + Registry example)
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 Negatives
Duplicates, rearrangement of order, delivery delay, "poisonous" messages (dead-letter).
Large messages (near-limit), unrecognized schema versions.
7) Contract-aware plugs
7. 1 Pact (CDC mocks)
Consumer generates expectations → pact file → provider verifies on the stand.
Pact stub server plays expectations for client integration tests.
7. 2 OpenAPI/Protobuf → stable generation
Tools that raise the mock server from the specification (including Prism, openapi-mock, grpc-mock).
Include negative examples/codes in the specification: this is also a contract.
8) Network and chaos: simulation of failures
Delays and jitter: fixed/distributed; check deadlines and per-try timeout.
Timeouts/breaks: half-open connections, RST, reset stream H2, 503/Retry-After.
Packet loss/duplicate: for gRPC/streams.
Tools: Toxiproxy, MockServer (fault injection), xk6-disruptor, netem in CI.
toxiproxy-cli toxic add psp --type latency --latency 300 --jitter 100
9) Data, secrets and determinism
Redact and synthetics: no PII in fixes; money - decimal/strict formatting.
Time fixation: fake clock; "yesterday/today" - control.
Idempotency: same'Idempotency-Key '→ same response.
Generators: factories/builders of data with transparent values (e. g., `test_user_001`).
Versioning fixes (tags), do not store "removed" answers without mediation.
10) CI/CD and environments
Matrix: unit (in-process fakes) → component (local virtualization) → integration (minimum moks, Testcontainers).
Artifacts: pact files, OpenAPI snapshots, ioc server logs, PCAP for drops.
Parallelism: unique ports/key prefixes; insulation of containers.
Gate: contract green (CDC verify), specification valid (lint), negatives passed.
11) Antipatterns
Moki "copy" defects in real service → false confidence. Treated with contracts and periodic record/verify.
The "macromocks" of the whole world in every test → fragility, expensive mainstream. Make thin ports and ACLs.
Moki in E2E where real integration is needed (especially payments/webhooks with HMAC/mTLS).
Flakes due to time/random/network racing → use fake clock, deterministic seats.
Secrets in fixes/repositories. Secrets - only through secret storage CI.
12) Specifics of iGaming/Finance
Payments/withdrawals: Mokes must support 'Idempotency-Key', 'Retry-After', HMAC/mTLS, sanction codes and 'long' responses.
Bonus logic/anti-fraud: velocity/429 scenarios, ATO/challenge, risk solutions' allow/deny/challenge'with TTL.
KYC/AML: sandbox responses by KYC levels, negatives (mismatch, invalid documents), webhooks with anti-replay ('X-Timestamp' window).
Jurisdictions/Tenants: Required 'X-Tenant/X-Region' headings, different response profiles.
13) Mini recipes (cheat sheet)
Repeat payment: WireMock "Scenarios" - first '201', second '409 duplicate'.
Slow PSP: MockServer 'responseDelay' + checking per-try timeout on client.
Webhooks: local HTTP server + HMAC signature verification; replay after 5 seconds does not create a double.
Kafka duplicates: post the same message twice; handler must be idempotent.
gRPC statuses: matrix of 'codes' tests (InvalidArgument, DeadlineExceeded, ResourceExhausted).
14) Prod Readiness Checklist
- Ports/adapters are highlighted; integrations are hidden behind interfaces.
- For HTTP/gRPC - there are contract-aware stabs (Pact/OpenAPI/Proto) with negatives.
- For brokers - Testcontainers + Registry; duplicate/order/large message tests.
- Chaos: delays, timeouts, reset, 429/503 with 'Retry-After'; the network is emulated (Toxiproxy/netem).
- Fixtures without PII; fake clock; idempotency is minted.
- CI matrix: unit → component → integration; log/contract artifacts are preserved.
- Provider sandboxes: keys are separated, endpoints are configured, there is a runbook.
- Record/Replay is updated on schedule, traces are edited.
- flaky metrics and test durations under control; alerts at growth.
15) TL; DR
Isolate integrations through thin ports and use the right tool for the task: stubs for simple cases, mocks for verification of interactions, fakes for realistic behavior, service virtualization and chaos for network and rare errors. Make the moki contract-conscious (Pact/OpenAPI/Proto), keep the fixes deterministic and PII-free, simulate delays/timeouts/429/5xx. In CI, build a pyramid: unit → component → integration; release block with red contracts. For payment/CCM paths, consider HMAC/mTLS, idempotence and negative scenarios.