Oprava testovací sady

Testy lokálně projdou, ale v CI selhávají: jak najít rozdíl

Test, který na notebooku projde a v CI selže, si neprotiřečí. Běžel ve dvou odlišných podmínkách. Cílem diagnostiky proto není opakovat jej tak dlouho, až zezelená, ale zjistit, který rozdíl mění výsledek.

Proč se výsledek lokálního běhu a CI liší

CI neboli průběžná integrace spouští sestavení a testy na samostatném runneru – stroji nebo procesu určeném k provedení automatických kroků. Runner může mít jiný operační systém, výkon, časové pásmo, verzi prohlížeče, přístupy i testovací data než lokální počítač. Čím přesněji tyto podmínky zachytíte, tím snáze selhání zopakujete a opravíte.

Nejprve uchovejte důkazy z původního selhání

Nezačínejte pouze novým během. Uložte název testu, commit a sestavení aplikace, přesný příkaz, čas běhu, runner, prohlížeč a první chybovou zprávu. Připojte konzolový výstup testu, relevantní aplikační a síťové logy a identifikátor požadavku, pokud jej systém používá. Důležitá je první příčina; další chyby mohou být jen jejím následkem.

U UI testů mohou pomoci trace, snímek obrazovky nebo video. Nejsou však automaticky dostupné u každého nástroje ani běhu. Například Playwright má záznamy vypnuté, dokud je nezapne konfigurace, a umožňuje je uchovat jen při selhání či při opakovaném pokusu. Trace potom dokáže zobrazit jednotlivé kroky, stav stránky, konzoli a síťovou aktivitu v Trace Vieweru.

Artefakt musí odpovídat chybnému pokusu. Video z opakovaného pokusu (retry), který už prošel, nemusí ukázat původní problém. Záznamy zároveň mohou obsahovat osobní údaje, tokeny nebo vyplněné formuláře, proto jim nastavte omezený přístup a dobu uchovávání.

Realistický příklad: objednávka selže pouze v nočním CI běhu

Představte si test, který vytvoří objednávku s dnešním datem doručení. Vývojář ho v deset dopoledne spustí v Praze a test projde. CI runner běží v UTC, test se spustí krátce po místní půlnoci a API už vypočítá jiný „dnešní“ den než prohlížeč. Snímek ukáže pouze nesprávné datum v potvrzení; bez údaje o časovém pásmu vypadá chyba jako náhodný problém rozhraní.

Ve stejné sadě běží čtyři workery neboli souběžné pracovní procesy. Každý používá účet e2e-customer@example.test a před testem vyprázdní jeho košík. Jeden scénář tak může odstranit položky druhému. Lokálně běží ve výchozím nastavení jen jeden worker, proto se konflikt neprojeví. Lokální počítač má navíc v cache starší verzi prohlížeče, zatímco CI po čisté instalaci použije verzi určenou souborem uzamykajícím verze závislostí (lockfile) a obrazem runneru.

Nejde o jednu „CI chybu“, ale o tři samostatné hypotézy: čas, souběh a verzi prostředí. Dobrý diagnostický postup je nemění současně. Nejprve zopakuje CI běh s jedním workerem, poté nastaví stejné časové pásmo a nakonec porovná přesné verze. Tak lze prokázat, která podmínka mění výsledek a které rozdíly byly pouze doprovodné.

Vytvořte systematické porovnání prostředí

Místo náhodného měnění timeoutů porovnejte lokální a CI běh ve stejných kategoriích:

  1. Kód a příkaz: stejný commit, sestavený artefakt, pracovní adresář, testovací tagy a konfigurační soubory. Ověřte, zda lokálně opravdu spouštíte stejný příkaz jako pipeline.
  2. Verze: runtime, balíčky podle lockfile, prohlížeč, ovladače, operační systém a obraz kontejneru. U vzdáleného Playwright serveru má podle oficiální dokumentace verze v testech odpovídat verzi v kontejneru.
  3. Konfigurace: proměnné prostředí, přepínače funkcí (feature flags), základní URL, proxy, certifikáty, režim bez zobrazeného okna (headless) a oprávnění. Do diagnostiky zapisujte názvy a bezpečné otisky nastavení, nikoli hodnoty hesel.
  4. Čas a lokalita: časové pásmo, locale, formát data, systémové hodiny a scénáře na přelomu dne či měsíce. Prohlížeč může mít navíc vlastní emulovanou lokalitu nebo zónu.
  5. Data a přístupy: migrace databáze, připravené záznamy, stav účtu, role, platnost tokenu, dostupnost tajného přístupového údaje (secretu) a chování externí služby. Chybějící secret se může projevit jako obyčejné neúspěšné přihlášení.
  6. Zdroje a síť: výkon CPU a paměti, latence, DNS, porty, firewall a rychlost startu aplikace. Pomalejší runner často pouze odhalí čekání navázané na čas místo na skutečný stav.

Výsledek zapište jako krátké porovnání prostředí, tedy „environment diff“: co je stejné, co se liší a co ještě neznáte. Tak se z domněnek stanou ověřitelné hypotézy.

Přeneste podmínky, ne jen test

Nejprve spusťte selhávající test z čerstvě staženého repozitáře (clean checkout) se stejným lockfile a stejným příkazem. Pokud pipeline používá kontejner, zkuste tentýž obraz lokálně. Naopak diagnostický krok v CI může vypsat bezpečné verze nástrojů, locale a časovou zónu. Oficiální návod pro Playwright v CI například odděluje instalaci balíčků, prohlížečů a samotný běh, takže lze ověřit každou fázi.

Pokud test samostatně projde, ale v celé sadě selhává, zaměřte se na souběh a sdílený stav. Dočasně nastavte jeden worker a porovnejte výsledek. Potom hledejte stejný účet, název záznamu, soubor, port nebo pořadí testů. Jeden worker je diagnostický experiment, ne konečná oprava; cílem je izolovat data tak, aby testy mohly bezpečně běžet souběžně.

Pokud selže i samostatně, měňte pouze jednu podmínku: časové pásmo, verzi, konfiguraci nebo zdroj dat. U každého pokusu si zapište výsledek. Když jsou pády nepředvídatelné v obou prostředích, jde spíše o nestabilitu, kterou je třeba měřit pomocí historie běhů, ne pouze o rozdíl lokálně versus CI.

Jak potvrdit, že jste našli příčinu

Shoda jednoho úspěšného běhu ještě není důkaz. Hypotéza je přesvědčivá tehdy, když dokážete výsledek ovládat: za původní podmínky test opakovaně selže a po její cílené změně projde bez dalších zásahů. U konfliktu účtů například ponechte stejný kód aplikace i testu, ale přidělte každému workeru vlastní účet. Poté zkuste sadu opakovaně se stejným počtem workerů jako v CI.

Pro každou hypotézu si připravte malý experiment:

  1. zapište očekávání, například „při jednom workeru konflikt zmizí“;
  2. určete jedinou měněnou proměnnou a vše ostatní zmrazte;
  3. několikrát zopakujte chybnou i opravenou konfiguraci;
  4. zkontrolujte, zda se nezměnil pouze typ nebo místo selhání;
  5. přidejte automatickou kontrolu, která návrat problému odhalí.

Poslední bod odlišuje diagnostiku od trvalé opravy. Pokud byl problémem chybějící secret, pipeline má selhat hned při kontrole povinné konfigurace, ne až o pět minut později v přihlašovacím testu. Pokud šlo o časové pásmo, nastavte je explicitně nebo testujte hraniční data řízenými hodinami. Jestliže byla příčinou společná data, generujte identifikátor podle běhu a workera místo ponechání sériového režimu.

Po opravě porovnejte alespoň tyto důkazy: stejný test projde z čistého lokálního checkoutu i v CI, projde samostatně i v celé sadě a diagnostický výstup uvádí rozhodující verze a konfiguraci. U chyby spojené se souběhem spusťte cílovou skupinu s plánovanou paralelizací, ne pouze jednou sériově. U problému spojeného s časem ověřte také hranici, na které původně selhával.

Do incidentu nebo úkolu zapište příčinu ve formě „podmínka → mechanismus → projev“. Například: „Dva workery upravovaly stejný košík, proto jeden odstranil položku před ověřením druhého a test hlásil nesprávnou částku.“ Takový záznam je užitečnější než „zvýšený timeout“ a lze jej převést na pravidlo pro celou sadu.

Čemu se při opravě vyhnout

Vyšší timeout může potvrdit podezření na pomalou operaci, ale neměl by zůstat jedinou opravou bez ověření stavu. Retry pomůže získat další důkaz, ale úspěch na druhý pokus nesmí překrýt první selhání. Stejně tak nepřepínejte pipeline natrvalo na sériový běh, pokud problémem zůstávají společná data.

Neměňte ani produkční kód, test, runner a data současně. Takový výsledek sice může být zelený, ale neřekne, co chybu odstranilo a zda se vrátí.

Co tím získáte

Reprodukovatelný rozdíl zkracuje cestu od červeného výsledku k příčině. Tým dokáže rozlišit chybu aplikace, chybu testu, chybějící konfiguraci a konflikt dat. Zároveň vznikne seznam údajů, které má každý CI běh ukládat, takže další selhání nezačíná bez kontextu.

Další krok

Při příštím pádu vytvořte jednu stranu s příkazem, verzemi, konfigurací, časem, daty a počtem workerů pro oba běhy. Potom přenášejte rozdíly do lokálního prostředí nebo CI po jednom. Pokud je sada dlouhodobě nejasná a chybějí jí důkazy, postup pro převzetí selhávající sady pomůže nejprve obnovit kontrolu nad jejím spuštěním a vlastnictvím.

Související témata

Mohlo by vás také zajímat

Spolehlivé výsledky jsou důležitější než počet testů

Změříme nestabilitu, prověříme pravděpodobné příčiny náhodných selhání a sadu stabilizujeme v dohodnutém rozsahu.