Mocking et stubs pour les intégrations
1) Pourquoi avez-vous besoin de mouchoirs et de bouchons
Les intégrations avec les fournisseurs de paiement, les services KYC, les courtiers de messages, le CRM, etc. rendent les tests lents, instables et coûteux. Les mouchoirs/bouchons permettent :- Isoler la logique du service de l'environnement instable ;
- déterminer les réponses et les erreurs ;
- Reproduire les cas limites rares (timeouts, 429/5xx, non-consistance) ;
- exécuter les tests localement et en IC de manière rapide et prévisible.
2) Termes et taxonomie
Stub est un simple bouchon à réponse fixe, sans vérification des interactions.
Mock est un objet qui attend les appels et les vérifie (ordre/nombre/arguments).
Fake est une implémentation simplifiée (par exemple, un référentiel In-Memory) avec un comportement réel.
Spy est une enveloppe qui enregistre les appels réels.
Service Virtualization est un service externe « virtuel » avec des scripts, des états et des fonctionnalités réseau.
Record/Replay - enregistrement du trafic réel et lecture ultérieure (avec filtres/édition).
3) Modèles architecturaux pour la testabilité
Ports & Adaptateurs (Hexagonal) : mettez l'intégration par interfaces - facile à remplacer par fake/mock.
Couche anticorruption (ACL) : un module traduit un modèle externe en un modèle de domaine - moins de points de moka.
Clients contract-aware : génération par OpenAPI/Protobuf → moins d'incohérences manuelles.
Caractéristiques drapeaux et modes sandbox : clés/endpoints sécurisés pour la stabilité du fournisseur.
4) HTTP : outils et exemples
4. 1 WireMock (standalone/Java DSL)
JSON-b :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 (avec contrôle du corps et 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 (dynamique/vérification)
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)
Enregistrez le trafic contre le « bac à sable » du fournisseur, nettoyez le PII, fixez comme fixture.
En mode simulate, ajoutez les variations : 200/4xx/5xx, les retards et la fenêtre « 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 Génération de la stabilité
Générez un serveur par '.proto', implémentez des méthodes avec des réponses surveillées.
Vérifiez les métadonnées (headers), les statuts ('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 pour les négatifs
grpcurl -plaintext -d '{"amount":0}' localhost:50051 payouts. Payouts/Create
6) Messages et strips : Kafka/RabbitMQ
6. 1 Schema-aware moki
Utilisez Schema Registry et validez Avro/JSON-Schema/Protobuf dans les tests.
Test de production : le message correspond au schéma ; Test de consommation : accepte l'ancienne et la nouvelle version.
6. 2 Testamentaires (exemple 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 Négatifs
Doublons, réorganisation de l'ordre, retard de livraison, messages « toxiques » (dead-letter).
Grands messages (near-limit), versions non reconnues des schémas.
7) Bouchons Contract-aware
7. 1 Pact (CDC mocks)
Consumer génère les attentes → le fichier pact → le fournisseur vérifie sur le stand.
Pact stub server reproduit les attentes pour les tests d'intégration du client.
7. 2 OpenAPI/Protobuf → génération de stab
Outils qui soulèvent le serveur mok de la spécification (p. ex. Prism, openapi-mock, grpc-mock).
Inclure des exemples/codes négatifs dans la spécification : c'est aussi un contrat.
8) Réseau et chaos : simulation d'échec
Retards et jitter : fixes/distribués ; vérifiez les dédelines et les timeout per-try.
Temporisation/discontinuité : connexion half-open, RST, réinitialisation du flux H2, 503/Retry-After.
Pertes par lots/doublons : pour gRPC/strims.
Outils : Toxiproxy, MockServer (fausse injection), xk6-disruptor, netem dans CI.
toxiproxy-cli toxic add psp --type latency --latency 300 --jitter 100
9) Données, secrets et déterminisme
Redact et synthétique : pas de PII dans les ficelles ; argent - décimal/formatage strict.
Fixation du temps : fake clock ; « hier/aujourd'hui » - contrôler.
Idempotence : la même 'Idempotency-Key' → la même réponse.
Générateurs : usines/afficheurs de données avec des valeurs transparentes (e. g., `test_user_001`).
Versez les fiches (balises), ne stockez pas les réponses « enregistrées » sans médiation.
10) CI/CD et environnement
Matrice : unit (in-process fakes) → component (virtualisation locale) → integration (mokes minimum, Testcontainers).
Artefacts : fichiers pact, snapshots OpenAPI, logs de serveur mox, PCAP en cas de chute.
Parallèle : ports/préfixes de clés uniques ; isolation des conteneurs.
Gate : le contrat est vert (CDC verify), la spécification est validée (lint), les négatifs sont passés.
11) Anti-modèles
Les mokes « copient » les défauts du service réel → la fausse confiance. Il est traité avec des contrats et un record périodique/verify.
Les « macromoques » du monde entier à chaque épreuve → la fragilité, la maintenance chère. Faites des ports fins et ACL.
Moki dans les E2E où une intégration réelle est nécessaire (en particulier les paiements/webhooks avec HMAC/mTLS).
Flakes en raison du temps/random/course en réseau → utiliser fake clock, sièges déterministes.
Secrets dans les fiches/référentiels. Secrets - seulement à travers le secret-stockage CI.
12) Spécificité de l'iGaming/Finance
Paiements/conclusions : les mokes doivent soutenir 'Idempotency-Key', 'Retry-After', HMAC/mTLS, les codes de sanctions et les réponses « longues ».
Bonus-logique/antifrod : scénarios velocity/429, ATO/challenge, solutions de risque 'allow/deny/challenge' avec TTL.
KYC/AML : réponses sandbox par niveau KYC, négatifs (mismatch, documents non valides), webhooks avec anti-replay ('X-Timestamp'fenêtre).
Juridictions/tenants : titres obligatoires « X-Tenant/X-Region », profils de réponse différents.
13) Mini recettes (triche)
Répétition de paiement : WireMock « Scenarios » est le premier '201', le second '409 duplicate'.
PSP lent : MockServer 'responseDelay' + vérifie per-try timeout dans le client.
Webhooks : serveur HTTP local + vérification de la signature HMAC ; une répétition dans 5 secondes ne crée pas de prise.
Kafka-doublons : publiez le même message deux fois ; handler est obligé d'être idempotent.
États gRPC : matrix des tests par 'codes' (InvalidArgent, DeadlineExceeded, ResourceExhausted).
14) Chèque-liste prod-prêt
- Ports/adaptateurs mis en évidence ; les intégrations sont cachées derrière les interfaces.
- Pour HTTP/gRPC - il y a une meute contract-aware (Pact/OpenAPI/Proto) avec des négatifs.
- Pour les courtiers - Testcontainers + Registry ; tests de duplication/ordre/messages volumineux.
- Chaos : retards, temporisation, reset, 429/503 avec « Retry-After » ; le réseau est émulé (Toxiproxy/netem).
- Fictions sans PII ; fake clock; l'idempotence est frappée.
- Matrice CI : unité → composant → intégration ; les artefacts des loges/contrats sont conservés.
- Sandbox des fournisseurs : les clés sont séparées, les endpoints sont configurés, il y a un runbook.
- Record/Replay est mis à jour selon les horaires, les tracas sont édités.
- Métriques de flaky et durées des tests sous contrôle ; alerte à la croissance.
15) TL; DR
Isolez les intégrations via des ports fins et utilisez l'outil approprié pour la tâche : stubs pour les cas simples, mocks pour vérifier les interactions, fakes pour un comportement réaliste, service virtualization et chaos - pour les erreurs réseau et rares. Rendre les motocycles conscients du contrat (Pact/OpenAPI/Proto), garder les fictions déterministes et sans PII, simuler les retards/délais/429/5xx. En CI, construisez une pyramide : unit → component → integration ; bloquer la libération dans les contrats rouges. Pour les chemins de paiement/CUS, prenez en compte le HMAC/mTLS, l'idempotence et les scénarios négatifs.