Mocking y stubs para integraciones
1) Por qué se necesitan mokes y tapones
Las integraciones con proveedores de pago, servicios KYC, corredores de mensajes, CRM, etc. hacen que las pruebas sean lentas, inestables y costosas. Los mokes/tapones permiten:- aislar la lógica del servicio de un entorno inestable;
- Determine las respuestas y los errores;
- reproducir casos fronterizos raros (timeouts, 429/5xx, no consistencia);
- ejecutar pruebas localmente y en CI de forma rápida y previsible.
2) Términos y taxonomía
Stub es un simple enchufe de respuesta fija, sin comprobaciones de interacciones.
Mock es un objeto que espera llamadas y las verifica (orden/cantidad/argumentos).
Fake es una implementación simplificada (por ejemplo, un repositorio In-Memory) con un comportamiento real.
Spy es un envoltorio que registra las llamadas reales.
Virtualización de servicios: servicio externo «virtual» con scripts, estado y características de red.
Record/Replay - Grabación del tráfico real y posterior reproducción (con filtros/revisión).
3) Patrones arquitectónicos para la probabilidad
Ports & Adapters (Hexagonal): permite la integración por interfaces, fácil de reemplazar por fake/mock.
Capa anticorrupción (ACL): un módulo convierte un modelo externo en un dominio - menos puntos de moca.
Clientes de contrato-aware: generación por OpenAPI/Protobuf → menos inconsistencias manuales.
Banderas de características y modos sandbox: llaves/endpoints seguros para la estabilidad del proveedor.
4) HTTP: herramientas y ejemplos
4. 1 WireMock (standalone/Java DSL)
JSON-rupia: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 (con verificación corporal y variaciones):
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 (dinámica/verificación)
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)
Registre el tráfico contra el «sandbox» del proveedor, limpie la PII, fije como fixture.
En el modo simulate, agregue variaciones: 200/4xx/5xx, latencia y «flaky» de la ventana.
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 Generación estable
Genere el servidor por '.proto', implemente métodos con respuestas controladas.
Compruebe los metadatos (headers), los estados ('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 para negativos
grpcurl -plaintext -d '{"amount":0}' localhost:50051 payouts. Payouts/Create
6) Mensajes y Streams: Kafka/RabbitMQ
6. 1 Moki Schema-aware
Utilice el Registro de Schema y valide Avro/JSON-Schema/Protobuf en las pruebas.
Prueba de producto: el mensaje coincide con el esquema; Prueba de consumo: acepta versiones antiguas y nuevas.
6. 2 Testcontainers (ejemplo de 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 Negativos
Duplicados, reordenamiento, retraso en la entrega, mensajes «venenosos» (dead-letter).
Mensajes grandes (near-limit), versiones no reconocidas de los esquemas.
7) Contrato-aware tapones
7. 1 Pact (CDC mocks)
Consumer forma las expectativas → el archivo de paquete → el proveedor verifica en la cabina.
Nat stub server reproduce las expectativas de las pruebas de integración del cliente.
7. 2 OpenAPI/Protobuf → generación de estabilización
Herramientas que levantan el servidor mok de la especificación (como Prism, openapi-mock, grpc-mock).
Incluya ejemplos/códigos negativos en la especificación: también es un contrato.
8) Red y caos: simulación de fallos
Latencias y jitter: fijo/distribuido; compruebe los deduplines y el tiempo de espera per-try.
Tiempos/roturas: half-open conexiones, RST, reset flujo H2, 503/Retry-After.
Pérdidas/duplicados por lotes: para gRPC/streams.
Herramientas: Toxiproxy, MockServer (inyección falsa), xk6-disruptor, netem en CI.
toxiproxy-cli toxic add psp --type latency --latency 300 --jitter 100
9) Datos, secretos y determinismo
Redact y sintética: ningún PII en fixtures; dinero - decimal/formato estricto.
Fijación de tiempo: fake clock; «Ayer/hoy» - controlar.
Idempotencia: la misma 'Idempotency-Key' → la misma respuesta.
Generadores: fábricas/fabricantes de datos con valores transparentes (e. g., `test_user_001`).
Versione los fixtures (etiquetas), no almacene las respuestas «retiradas» sin mediar.
10) CI/CD y entorno
Matriz: unit (in-process fakes) → component (virtualización local) → integración (mínimo de mocos, Testcontainers).
Artefactos: archivos de pactos, snapshots OpenAPI, registros de servidores moc, PCAP en caídas.
Paralelismo: puertos/prefijos de clave únicos; aislamiento de contenedores.
Puerta: contrato verde (CDC verify), la especificación es válida (lint), los negativos pasados.
11) Antipattern
Los mokes «copian» los defectos del servicio real → la falsa confianza. Se trata con contratos y record/verify periódico.
«Macromoquis» de todo un mundo en cada prueba → fragilidad, querida maintenance. Haga puertos delgados y ACL.
Moki en E2E donde se necesita una integración real (especialmente pagos/webhooks con HMAC/mTLS).
Flakes debido al tiempo/random/carreras en red → use fake clock, sides deterministas.
Secretos en fixtures/repositorios. Los secretos son sólo a través de la bóveda secreta de CI.
12) Especificidad de iGaming/finanzas
Pagos/conclusiones: los mokes deben mantener 'Idempotency-Key', 'Retry-After', HMAC/mTLS, códigos sancionadores y respuestas «largas».
Lógica de bonificación/antifraude: escenarios velocity/429, ATO/challenge, soluciones de riesgo 'allow/deny/challenge' con TTL.
KYC/AML: respuestas sandbox por niveles KYC, negativos (mismatch, documentos inválidos), webhooks con anti-replay (ventana 'X-Timestamp').
Jurisdicciones/tenantes: títulos obligatorios 'X-Tenant/X-Region', diferentes perfiles de respuesta.
13) Mini recetas (spargle)
Repetición de pago: WireMock «Scenarios» es el primer '201', el segundo '409 duplicate'.
PSP lento: MockServer 'responseDelay' + comprobación del tiempo de espera per-try en el cliente.
Webhooks: servidor HTTP local + verificación de firma HMAC; la repetición después de 5 segundos no crea una toma.
Kafka-duplicados: publicar el mismo mensaje dos veces; hendler está obligado a ser idempotente.
gRPC-status: matrix test por 'codes' (InvalidArgument, DeadlineExceeded, ResourceExhausted).
14) Lista de comprobación prod
- Puertos/adaptadores seleccionados; las integraciones están ocultas detrás de las interfaces.
- Para HTTP/gRPC - Hay bandadas de contrato-aware (Nat/OpenAPI/Proto) con negativos.
- Para corredores - Testcontainers + Registry; pruebas duplicadas/orden/mensajes grandes.
- Caos: retrasos, temporeros, reset, 429/503 con 'Retry-After'; se emula la red (Toxiproxy/netem).
- Fixturas sin PII; fake clock; se comprueba la idempotencia.
- Matriz CI: unidad → composición → integración; los artefactos de logs/contratos se conservan.
- Sandbox de proveedores: las llaves están separadas, los endpoints están configurados, hay un runbook.
- Record/Replay se actualiza según lo programado, los tracks se editan.
- Métricas de flaky y duración de las pruebas bajo control; alertas durante el crecimiento.
15) TL; DR
Aísle las integraciones a través de puertos delgados y utilice la herramienta adecuada para la tarea: stubs para casos simples, macks para la verificación de interacciones, fakes para comportamientos realistas, virtualización de servicios y chaos para errores de red y raros. Haga que los mokes sean contractuales-conscientes (Nat/OpenAPI/Proto), mantenga los fixtures deterministas y sin PII, simule retrasos/timeouts/429/5xx. En CI construye una pirámide: unit → component → integration; bloquee la liberación con contratos rojos. Para las rutas de pago/CUS, considere HMAC/mTLS, idempotencia y escenarios negativos.