Contract tests i API tests: publiczna umowa systemu
Zmiana pola w odpowiedzi API często wygląda jak refactor.
Kod jest czystszy.
Testy jednostkowe przechodzą.
Backend zwraca nowy kształt danych.
Problem zaczyna się dopiero wtedy, kiedy frontend, worker albo starsza aplikacja mobilna nadal oczekuje starej umowy.
To jest miejsce dla contract tests i API tests.
Co to za rodzaj testu
API test sprawdza zachowanie publicznego interfejsu.
Może dotyczyć:
REST endpoint
GraphQL query
RPC method
webhook
event consumer
public SDK
Contract test sprawdza umowę między producentem i konsumentem.
Umowa mówi:
co wolno wysłać
co można dostać
które pola są wymagane
które pola są opcjonalne
jak wyglądają błędy
co jest kompatybilną zmianą
API test może być jednostronny: system wystawia endpoint i sprawdzamy jego odpowiedź.
Contract test jest relacyjny: istnieje producent i konsument, a test pilnuje, żeby ich oczekiwania się nie rozjechały.
Schema tests
Schema test jest blisko tej samej warstwy.
Sprawdza, czy dane pasują do schematu:
OpenAPI
JSON Schema
GraphQL schema
AsyncAPI
Avro
Protobuf
Schema test nie udowadnia, że zachowanie biznesowe jest poprawne.
Udowadnia, że kształt danych mieści się w ustalonej strukturze.
To ważne, bo wiele awarii integracyjnych nie zaczyna się od algorytmu.
Zaczyna się od pola, które zniknęło, zmieniło typ albo stało się wymagane.
Co się dzieje, kiedy ich nie ma
Bez tych testów publiczna umowa zaczyna zależeć od pamięci zespołu.
Ktoś zmienia customerId na accountId.
Ktoś usuwa status, który "już nie jest używany".
Ktoś zmienia błąd 409 na 400, bo tak wygodniej w kontrolerze.
Każda z tych zmian może być lokalnie sensowna.
Ale dla konsumenta to może być breaking change.
Jeżeli testy łapią to dopiero przez E2E, problem jest już zasłonięty całą ścieżką użytkownika.
Jeżeli łapie to produkcja, mamy awarię kompatybilności.
Consumer-driven contracts
W systemach z wieloma konsumentami dobry kontrakt często wychodzi od konsumenta.
Konsument mówi:
potrzebuję tych pól
dla takiego requestu oczekuję takiej odpowiedzi
te błędy obsługuję
Producent uruchamia te oczekiwania u siebie.
To nie zastępuje testów producenta.
To dodaje brakującą informację: które fragmenty API są naprawdę używane i w jaki sposób.
Bez tego backend może utrzymywać formalny schemat, który wygląda dobrze, ale nie chroni realnych klientów.
Granica kompatybilności
Najważniejsze pytanie w contract testach brzmi:
czy ta zmiana jest kompatybilna dla istniejących konsumentów?
Dodanie opcjonalnego pola zwykle jest kompatybilne.
Usunięcie pola zwykle nie jest.
Zmiana typu zwykle nie jest.
Dodanie nowego wymaganego pola w requestcie prawie zawsze jest breaking change.
Zmiana semantyki bez zmiany schematu jest najtrudniejsza, bo schema test jej nie zobaczy.
Wtedy potrzebny jest API test opisujący zachowanie, nie tylko kształt.
Narzędzie ze stacka
Do API tests w backendzie Node wybrałbym Supertest.
Pozwala sprawdzić prawdziwe endpointy, status codes, headers i body bez uruchamiania pełnego środowiska.
Do contract tests dołożyłbym walidację względem OpenAPI albo JSON Schema.
W praktyce test powinien mówić:
endpoint zwraca zachowanie, którego oczekuję
odpowiedź mieści się w publicznym kontrakcie
Jeżeli API ma wielu konsumentów, schemat to za mało.
Wtedy warto dodać consumer-driven contracts, ale nadal trzymać je blisko pipeline producenta.
Kiedy to za mało
Contract test i API test nadal nie mówią, że użytkownik przejdzie całą ścieżkę.
Mogą potwierdzić, że endpoint działa, a kontrakt jest zgodny.
Nie potwierdzą, że przeglądarka, routing, stan UI, płatność i powrót użytkownika z bramki płatności składają się w całość.
Do tego potrzebne są E2E tests.