Logo GH

Контрактне тестування API

1) Навіщо контрактне тестування

Контракт фіксує очікування клієнта і обіцянки провайдера: маршрути/методи, заголовки, схеми тіл, статуси, семантика помилок і обмеження. Мета - ловити несумісні зміни до інтеграції і випускати версії безпечно, без важких E2E.

2) Підходи

Consumer-Driven Contracts (CDC): клієнт формує очікування (Pact і аналоги); провайдер регулярно їх верифікує.
Специфікаційний: контракт як єдине джерело істини (OpenAPI/Protobuf/GraphQL SDL); тести валідують реалізацію проти специфікації.
Подієвий: схеми повідомлень (Avro/JSON Schema/Protobuf) + правила сумісності в брокері/реєстрі.

3) HTTP/REST: специфікаційний потік

1. Контракт: OpenAPI 3. x (схеми, приклади, коди).
2. Лінт і статаналіз: стиль, обов'язкові поля, єдині коди.
3. Валідація реалізації: генератор тестів проти OpenAPI (schemathesis/Dredd-підхід) + ручні негативи.
4. Снапшоти: фіксуйте приклади відповідей, ETag семантику, заголовки ідемпотентності.

Приклад negative-контракту (фрагмент OpenAPI):
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 (Pact-підхід)

Життєвий цикл:

1. Consumer пише тест, формує pact-файл (очікування).

2. Публікація в брокер (артефакт).

3. Provider в CI піднімає сервіс (або контракт-стійку), верифікує pact'и.

4. Брокер обчислює can-i-deploy матрицю сумісності.

Приклад consumer-тесту (псевдо-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) gRPC/Protobuf контракти

Контракт -'.proto'з версіонуванням пакетів/служб.
Сумісність: не перевикористувати теги, тільки додавати нові з optional, не видаляти використовувані поля; резервувати номери.
Тести: генерація стаба сервера/клієнта, прокат автозгенеренних кейсів + негативи (unknown fields, size-limits).

6) Подієві контракти (Kafka/NATS/...)

Схеми: Avro/JSON Schema/Protobuf в Schema Registry.
Політика сумісності: 'BACKWARD'( часто достатньо) або'FULL'.
Тести продьюсера: валідує повідомлення проти схеми; тести консьюмера: приймає стару і нову версію.
Інваріанти: ключі ідемпотентності, порядок/повторюваність, семантика дедуплікації.

Приклад Avro-схеми (фрагмент):
json
{"type":"record","name":"PayoutCreated","fields":[
{"name":"payoutId","type":"string"},
{"name":"amount","type":"double"},
{"name":"currency","type":{"type":"string","logicalType":"iso-4217"}}
]}

7) Сумісність і версії

Backward-compatible (рекомендований мінімум): додавайте необов'язкові поля, не ламайте існуючі.
Forward-compatible: споживачі ігнорують невідомі поля.
Full: і те, і інше.
Версіонування: `path (/v1)`, `Accept: application/vnd. brand. v2+json`, `proto package v2`.
Deprecation-політика: вікно виводу (наприклад, 90 днів), що попереджають заголовки/події.

8) Негативні і помилки - це теж контракт

Стандартизуйте коди: 400/401/403/404/409/422/429/5xx, обов'язкові поля'code','message','trace _ id'.
Розміри/ліміти - частина контракту (413/414/431).
Ідемпотентність: поведінка при повторі (409 vs 201 same id).
Заголовки: `Retry-After` при 429/503, `Idempotency-Key`, `Content-Language` и т. п.

Шаблон помилки:
json
{ "code":"validation_error", "message":"amount must be ≥ 1", "trace_id":"..." }

9) Даними управляє контракт

Приклади/примірочні відповіді (examples) - живі, валідуються в CI.
Фікстури для CDC - мінімальні, детерміновані.
Генерація даних - property-based для чисел/дат; але не ламати стабільність снапшотів.

10) Пайплайн в CI/CD (референс)

1. Lint/validate: OpenAPI/Proto/Avro (`validate`, style-линер).
2. Publish: контракт як артефакт (брокер/реєстр).
3. Verify: провайдер проганяє CDC-пакети/специфікаційні тести.
4. can-i-deploy gate: без зеленої матриці реліз заборонений.
5. Diff: перевірка, що зміни сумісні (semantic diff).
6. Report: JUnit/HTML, список порушень/дефініцій.

Псевдо-матриця:
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) Інструменти (за класами задач)

Лінт/валідатори: openapi-linters, protobuf-lint, avro-tools.
CDC: Pact-сімейство/брокер, Spring Cloud Contract, Hoverfly (HTTP записи/реплеї).
Специфікаційні раннери: schemathesis/Dredd-подібний підхід, Postman test + JSON Schema.
Diff: semantic-diff OpenAPI/Proto/Avro (виявляє breaking-зміни).
Контейнери: Testcontainers для підняття провайдера/стійки контрактів.

12) Антипатерни

«Спец-док» окремо від коду → розсинхронізація. Зберігайте контракт поруч з сервісом.
Моки стороннього сервісу замість контракту → крихкість при апдейтах.
Випадкові відповіді/генерація без прив'язки до схеми → флейки.
Зміна типів/обов'язковості полів без версії.
Silent-розширення без повідомлень/депрекації.
Відсутність негативних контрактів і кодів помилок.

13) Специфіка iGaming/фінансів

Формалізуйте грошові поля: «amount» - decimal з масштабом, валюта - ISO-4217, інваріанти сум.
Контракти платежів/вебхуків: HMAC/mTLS, anti-replay ('X-Timestamp'вікно), ідемпотентність,'Retry-After'.
Регіональність/тенанти: обов'язкові заголовки'X-Tenant/X-Region', локалізація повідомлень.
Події: незмінні журнали (audit), ключі дедуплікації, гарантії доставки (at least once + ідемпотентні хендлери).

14) Приклади «скелетів» тестів

14. 1 Schemathesis-стиль (псевдо)

bash schemathesis run openapi. yaml --checks all --hypothesis-deadline=200

14. 2 Postman як специфікаційний раннер

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 Provider-верифікація CDC (псевдо)

bash pact-broker can-i-deploy --pacticipant wallets --version $SHA --to-environment staging

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

  • Контракти в репозиторії, CI валідує і публікує артефакти.
  • CDC включений для критичних інтеграцій; працює broker/matrix «can-i-deploy».
  • Політика сумісності (HTTP/gRPC/Events) задокументована; автоматичний semantic-diff.
  • Негативні контракти: помилки, ліміти розмірів, ідемпотентність,'Retry-After'.
  • Тест-дані детерміновані; снапшоти прикладів підтримуються.
  • Версіонування та deprecation: терміни, повідомлення, заголовки.
  • Для подій - Schema Registry і режим сумісності; продьюсер/консьюмер тестують обидві версії.
  • Артефакти: JUnit/HTML, звіти diff/verify, матриця сумісності.
  • Інцидент-процедура: швидкий rollback контракту/фіча-прапор, повідомлення інтеграторам.

16) TL; DR

Фіксуйте очікування в контрактах і проганяйте їх автоматично: CDC для клієнтських очікувань, специфікаційні тести для відповідності реалізації, реєстр схем для подій. Тримайте сувору політику сумісності і негативні контракти (помилки, ліміти, ідемпотентність). Не можна релізувати без зеленої can-i-deploy матриці і semantic-diff без breaking-змін.

Contact

Зв’яжіться з нами

Звертайтеся з будь-яких питань або за підтримкою.Ми завжди готові допомогти!

Telegram
@Gamble_GC
Розпочати інтеграцію

Email — обов’язковий. Telegram або WhatsApp — за бажанням.

Ваше ім’я необов’язково
Email необов’язково
Тема необов’язково
Повідомлення необов’язково
Telegram необов’язково
@
Якщо ви вкажете Telegram — ми відповімо й там, додатково до Email.
WhatsApp необов’язково
Формат: +код країни та номер (наприклад, +380XXXXXXXXX).

Натискаючи кнопку, ви погоджуєтесь на обробку даних.