03 — Testowanie i weryfikacja
Przykazanie III: Weryfikuj, nie deklaruj.
Dwie różne rzeczy, często mylone:
- Testy — zautomatyzowana siatka bezpieczeństwa, którą uruchamiasz wielokrotnie.
- Weryfikacja — dowód, że ta konkretna zmiana robi to, co miała, zaobserwowany, nie założony.
Obie są obowiązkowe. Test, który przechodzi, nie znaczy, że feature działa w przeglądarce; ręczna weryfikacja bez testów nie chroni przed regresją jutro.
Piramida (z projektu referencyjnego)
| Poziom | Narzędzie | Co pokrywa | Kiedy |
|---|---|---|---|
| Unit | pytest / Jest | logika czysta (normalizer, matcher, helpery, walidatory) | co commit |
| Integration | Supertest (HTTP) | trasy, auth-guardy, API — Umówiony sposób, w jaki dwa programy gadają ze sobą — jeden prosi, drugi odpowiada w ustalonym formacie. Przez API Twoja aplikacja łączy się z cudzymi usługami (płatności, mapy, AI). Klucz API traktuj jak hasło. JSON | co commit |
| E2E / browser | Playwright | realne ścieżki w przeglądarce, na osobnym porcie | przed deployem / przy UI |
| Smoke | skrypt (smoke.ps1) | „czy serwer wstaje i N tras zwraca poprawnie” | po restarcie / przed/po deployu |
Reguły, które się sprawdziły:
- Uruchamiaj testy przed commitem ścieżki krytycznej.
- Jest z
--runInBand, gdy serwer dev/preview chodzi (konflikt portów/DB). - Smoke test — Szybki test „czy w ogóle działa” zaraz po wdrożeniu — sprawdza najważniejsze ścieżki (np. logowanie). Łapie katastrofy w 30 sekund, zanim zobaczy je użytkownik. Tani sposób na spokojny sen po deployu. ma markery — sprawdza, że wyrenderowała się właściwa strona (np.
price-gatedla anonima, nie tylko HTTP 200). - Testy auth z obu stron — anonim odbity do logowania i zalogowany widzi treść.
„Weryfikuj, nie deklaruj” — w praktyce
Po zmianie obserwowalnej w aplikacji pokaż dowód, nie proś usera, żeby sam sprawdził:
- kod HTTP /
redirect_url(curl-o /dev/null -w), - fragment HTML potwierdzający (np.
og:imagewskazuje na właściwy plik), - liczby z bazy (ile kont, ile cen,
integrity_check: ok), - screenshot przy zmianach wizualnych.
Po deployu — smoke test na żywym serwerze (przez localhost za flagą maintenance), a
gdy znajdziesz błąd w oknie — napraw go w oknie, jeśli to trywialne i bezpieczne (w
projekcie referencyjnym tak złapaliśmy i naprawiliśmy zastane ERR_HTTP_HEADERS_SENT na /mapa).
Raport ma być uczciwy
- Testy padają → powiedz to z outputem, nie chowaj.
- Coś pominięto → powiedz, że pominięto.
- Gdy 2 testy padają z dryfu danych (np. cohort-fixture
85% vs 85%), a nie z regresji — odróżnij to jawnie i nie blokuj nimi deployu, ale zaproponuj follow-up (regeneracja fixture’ów). - „Zrobione i zweryfikowane” mów dopiero, gdy naprawdę zweryfikowane — bez hedgingu, ale i bez ściemy.
Liczby weryfikuj u źródła
Nie ufaj liczbie z pamięci ani z dokumentacji — odpytaj bazę/test. Dokumentacja się starzeje;
SELECT COUNT(*) nie kłamie. (Przykazanie X: „liczby weryfikuj”.)
Web — sprawdzony zestaw kontroli
Dla stron/projektów webowych ten zestaw testów już się w praktyce sprawdził (typowy zestaw to kilkadziesiąt metod i kilkaset subtestów) — przenoś go domyślnie:
- SEO meta (title/description per strona), canonical + hreflang — Oznaczenie, które mówi wyszukiwarce, w jakim języku jest strona i gdzie są jej wersje w innych językach. Bez tego wielojęzyczna strona myli Google — wersje językowe „walczą” o tę samą frazę., JSON-LD — Dane strukturalne: niewidoczny dla człowieka opis strony, który czyta wyszukiwarka (np. FAQ, autor, breadcrumbs). Otwiera „rich snippets” w Google — bogatsze wyniki, wyższy CTR..
- Dostępność: kontrast tokenów kolorów, nawigacja klawiaturą, sensowne
alt/aria. - Parytet EN↔PL (i każdej pary językowej): brakujący klucz/strona w jednym języku = test, który pada.
- Martwe linki wewnętrzne — żaden link w buildzie nie prowadzi w pustkę.
- Spójność motywu (theme cookie / dark-light) i poprawność builda (każda strona się wyrenderowała).
Anty-wzorce
- 🚫 „Powinno działać” jako konkluzja.
- 🚫 Uruchomienie tylko jednego testu i ogłoszenie „suite zielony”.
- 🚫 Pominięcie smoke testu po deployu, bo „przecież testy przeszły”.
- 🚫 Mylenie „kod się kompiluje” z „feature działa dla użytkownika”.
TDD — domyślny tryb pracy
Test najpierw, nie po fakcie. Cykl:
- Czerwony — napisz test, który opisuje oczekiwane zachowanie i pada.
- Zielony — najmniejsza zmiana w kodzie, aż test przechodzi.
- Refactor — posprzątaj przy zielonym suite (→ 02).
Bug naprawiasz tak samo: najpierw test odtwarzający błąd, potem fix — test zostaje jako regresja, żeby błąd nie wrócił.
Każda zmiana w commicie niesie test. Twarda reguła: commit, który zmienia zachowanie, a nie dodaje/zmienia testu, jest niekompletny. Nowy Endpoint — Pojedynczy „adres” w API, pod który wysyłasz zapytanie po konkretną rzecz (np. listę zamówień). Aplikacje rozmawiają przez endpointy — jeden endpoint = jedna funkcja, którą udostępniasz. → test trasy; nowy próg/fallback → test progu; naprawiony bug → test regresji. „Dodam testy później” = grzech (koniec nie nadchodzi). → 00, 08
Guard dowodzi incydent, nie fixture
Check napisany po awarii musi zostać odtworzony na realnych danych tej awarii, zanim mu zaufasz.
Fixture pisze ta sama głowa, która napisała buga, więc dziedziczy jej martwe pole: w projekcie referencyjnym
check świeżości danych przeszedł dziewięć zielonych testów jednostkowych, po czym nie wykrył tej właśnie
awarii, dla której powstał — porównanie było > tam, gdzie miało być >=, a zamrożone źródła stały
dokładnie na progu. Guard, który przepuszcza własny przypadek referencyjny, jest gorszy niż jego brak:
zamienia otwarte pytanie w fałszywy spokój. Wyceluj go w produkcję (albo snapshot), potwierdź, że odpala,
i dopiero wtedy zamroź próg w fixture — z jawnym testem na samym progu.
- Testuj kontrakt, nie implementację — inaczej refactor kruszy testy bez realnej regresji.
- Suite szybki i deterministyczny — wolny lub migający suite przestaje być uruchamiany;
izoluj I/O, ustaw seedy,
--runInBandprzy współdzielonym porcie/DB. - CI bramkuje — czerwone testy blokują merge i deploy; testy ścieżki krytycznej odpalasz przed commitem.