Testowanie kontraktów API
1) Dlaczego testy kontraktowe
Kontrakt przechwytuje oczekiwania klientów, a dostawca obiecuje: trasy/metody, nagłówki, schematy nadwozia, statusy, semantykę błędów i ograniczenia. Celem jest bezpieczne złapanie niezgodnych zmian przed integracją i wydaniem wersji bez ciężkich E2E.
2) Podejścia
Umowy konsumenckie (CDC): klient tworzy oczekiwania (pakt i analogie); dostawca regularnie je weryfikuje.
Specyfikacja: umowa jako pojedyncze źródło prawdy (OpenAPI/Protobuf/GraphQL SDL); badania potwierdzają wdrożenie w stosunku do specyfikacji.
W oparciu o zdarzenia: schematy wiadomości (Avro/JSON Schema/Protobuf) + broker/zasady zgodności rejestru.
3) strumień specyfikacji HTTP/REST
1. Kontrakt: OpenAPI 3. x (schematy, przykłady, kody).
2. Analiza Lint i Stat: styl, wymagane pola, jednolite kody.
3. Walidacja implementacji: generator testów anty-OpenAPI (schemathesis/Dredd approach) + ręczne negatywy.
4. Migawki: przechwytywanie odpowiedzi próbki, semantyka ETag, nagłówki idempotencji.
yaml paths:
/v1/payments:
post:
responses:
"201": { $ref: "#/components/responses/PaymentCreated" }
"409": { description: Duplicate by Idempotency-Key }
"422": { description: Schema/Business validation failed }
4) CDC (podejście paktowe)
Cykl życia:1. Konsument pisze test, generuje plik paktu (oczekiwania).
2. Publikacja w brokerze (artefakt).
3. Dostawca w CI podnosi usługę (lub stojak na zamówienie), weryfikuje pakt.
4. Broker oblicza macierz kompatybilności can-i-deploy.
Przykład testu konsumenckiego (pseudo-JS):js pact
.given("wallet exists")
.uponReceiving("get wallet")
.withRequest({ method:"GET", path:"/v1/wallets/w123", headers:{ "Authorization": term({generate:"Bearer x", matcher:/^Bearer\s.+/}) }})
.willRespondWith({
status: 200,
headers: { "Content-Type": "application/json" },
body: like({ id:"w123", currency: "EUR", balance: 0 })
});
5) Umowy gRPC/Protobuf
Umowa jest '.proto' z pakietu/usługi wersioning.
Kompatybilność: nie należy ponownie używać znaczników, dodawać tylko nowe z opcją, nie usuwać użytych pól; numery rezerwowe.
Testy: generacja dźgnięcia serwera/klienta, automatycznie generowany wynajem przypadków + negatywy (nieznane pola, limity wielkości).
6) Kontrakty na imprezy (Kafka/NATS/...)
Сбева: Avro/JSON Schema/Protobuf Мирана Сева (Rejestr Avro/JSON Schema).
Polityka zgodności jest 'BACKWARD' (często wystarczająco) lub 'FULL'.
testy producenta: zatwierdza komunikat w odniesieniu do programu; testy konsumenckie: akceptuje stare i nowe wersje.
Niezmienne: klucze idempotencji, kolejność/powtarzalność, semantyka deduplikacji.
json
{"type":"record","name":"PayoutCreated","fields":[
{"name":"payoutId","type":"string"},
{"name":"amount","type":"double"},
{"name":"currency","type":{"type":"string","logicalType":"iso-4217"}}
]}
7) Kompatybilność i wersje
Kompatybilność wsteczna (zalecane minimum): dodać opcjonalne pola, nie łamać istniejących.
Kompatybilność: konsumenci ignorują nieznane pola.
Pełne: oba.
Wersioning: 'path (/v1)', 'Accept: application/vnd. marki. v2 + json ', „proto package v2”.
Zasady odchylenia: okno wyjściowe (na przykład 90 dni), nagłówki/zdarzenia ostrzegawcze.
8) Negatywne i błędy są również umową
Kody standaryzacyjne: 400/401/403/404/409/422/429/5xx, obowiązkowe pola "code", "message", "trace _ id'.
Rozmiary/limity są częścią umowy (413/414/431).
Idempotencja: zachowanie powtarzania (409 vs 201 ten sam id).
Nagłówki: „Retry-After” na 429/503, „Idempotence-Key”, „Content-Language” itp.
json
{ "code":"validation_error", "message":"amount must be ≥ 1", "trace_id":"..." }
9) Dane zarządzane na podstawie umowy
Przykłady - live, zatwierdzone w CI.
Uchwyty dla CDC są minimalne, deterministyczne.
Generowanie danych - nieruchomości dla numerów/dat; ale nie złamać stabilności migawek.
10) Rurociąg w CI/CD (odniesienie)
1. Lint/validate: OpenAPI/Proto/Avro („validate”, styl-линей).
2. Publikacja: Umowa jako artefakt (broker/rejestr).
3. Sprawdź: dostawca prowadzi pakiety CDC/testy specyfikacji.
4. can-i-deploy gate: no release allowed without green matrix.
5. Diff-Sprawdza, czy zmiany są semantyczne diff.
6. Sprawozdanie: JUnit/HTML, lista naruszeń/definicji.
yaml jobs:
lint:...
publish-contract: needs: [lint]
verify-provider: needs: [publish-contract]
can-i-deploy:
if: always()
steps: [run: pact-broker can-i-deploy...]
11) Narzędzia (według klasy zadań)
Lint/validators: openapi-linters, protobuf-lint, avro-tools.
CDC: Pact family/broker, Spring Cloud Contract, Hoverfly (HTTP records/replays).
Biegacze specyfikacji: schemathesis/Dredd-like approach, Postman test + JSON Schema.
Diff: semantyczne-diff OpenAPI/Proto/Avro (wykrywa zmiany łamania).
Kontenery: Testcontainers do podniesienia dostawcy/biurko kontraktowe.
12) Antypattery
„Specjalny dok” oddzielnie od kodu → desynchronizacja. Trzymaj kontrakt w pobliżu usługi.
Moki usługi strony trzeciej zamiast umowy → kruchość podczas aktualizacji.
Losowe odpowiedzi/generacja bez wiązania z schematem → płatki.
Zmiana typów/pól obowiązkowych bez wersji.
Ciche rozszerzenia bez powiadomienia/zmniejszenia.
Brak negatywnych umów i kodów błędów.
13) Szczegóły dotyczące iGaming/Finance
Formalizacja pól pieniężnych: „kwota” - dziesiętna ze skalą, waluta - ISO-4217, niezmienne kwoty.
Kontrakty płatnicze/webhook: HMAC/mTLS, anty-replay (okno „X-Timestamp”), idempotencja, „Retry-After”.
Regionalność/najemcy: obowiązkowe nagłówki „X-Najemca/X-Region”, lokalizacja wiadomości.
Zdarzenia: niezmienne dzienniki (audyt), klucze deduplikacji, gwarancje dostawy (co najmniej raz + obsługujący idempotent).
14) Przykłady „szkieletów” badań
14. 1 Schemat w stylu (pseudo)
bash schemathesis run openapi. yaml --checks all --hypothesis-deadline=200
14. 2 Listonosz jako instruktor
js pm. test ("Scheme/v1/wallets/{ id} is valid," () => {
const schema = pm. collectionVariables. get("wallet_get_schema");
pm. expect(ajv. validate(JSON. parse(schema), pm. response. json())). to. be. true;
});
14. 3 Weryfikacja dostawcy CDC (Pseudo)
bash pact-broker can-i-deploy --pacticipant wallets --version $SHA --to-environment staging
15) Lista kontrolna gotowości Prod
- Umowy w repozytorium, CI zatwierdza i publikuje artefakty.
- CDC umożliwiające integrację krytyczną; broker/matrix „can-i-deploy” działa.
- Udokumentowana polityka zgodności (HTTP/gRPC/Events); automatyczne semantyczne-diff.
- Kontrakty negatywne: błędy, limity wielkości, idempotencja, „Retry-After”.
- Dane z badań są deterministyczne; migawki przykładów są obsługiwane.
- Wersioning i deprecation: terminy, powiadomienia, nagłówki.
- Dla zdarzeń - rejestr schematu i tryb kompatybilności; Producent/konsument testuje obie wersje.
- Artefakty: JUnit/HTML, raporty diff/verify, matryca kompatybilności.
- Procedura incydentu: szybki zwrot/flaga funkcji umowy, powiadomienie integratorów.
16) TL; DR
Przechwytywanie oczekiwań w umowach i uruchamianie ich automatycznie: CDC dla oczekiwań klientów, testy specyfikacji do dopasowania implementacji, schemat rejestru wydarzeń. Zachować ścisłą politykę zgodności i negatywne umowy (błędy, ograniczenia, idempotencja). Nie można zwolnić bez macierzy green can-i-deploy i semantic-diff bez łamania zmian.