← Zpět na články

Produkce jako testovací sada

V minulém díle jsem psal o tom, jak jsem přešel od ručně psaných extraktorů k pravidlům. Slíbil jsem, že se vrátím k testování, protože bez něj by celý ten refaktoring byl spíš hazard než inženýrství. Dnes tedy o tom, jak testuji aplikaci, jejímž vstupem je něco tak nevyzpytatelného jako PDF od banky.

Unit testy nestačí

Na začátku jsem psal klasické unit testy. Parsování částky, parsování data, rozpoznání IBANu. Ty mám dodnes a jsou užitečné — třeba když zjistíte, že slovenská banka píše mínus za číslem, nebo že jedna česká banka dává mezi tisíce nezlomitelnou mezeru, která vypadá úplně stejně jako obyčejná.

Jenže většina chyb v parseru výpisů nevzniká v parsování jedné hodnoty. Vzniká v tom, že se transakce rozdělí na špatném řádku, že se na konci stránky ztratí poslední řádek, nebo že se do transakcí dostane souhrnný řádek „Celkem připsáno“. A takové chyby unit testem na jedné funkci nenajdete. Potřebujete otisk skutečného výpisu a jasný výsledek.

Golden testy

A tak jsem sáhl po přístupu, kterému se říká golden nebo snapshot testy. Princip je jednoduchý: vezmu skutečný výpis, nechám jej zanonymizovat, až potom zpracovat, výsledek uložím do souboru a ručně zkontroluji. Od té chvíle každé spuštění testů zpracuje zanonymizovaný otisk znovu a porovná výsledek s uloženým souborem bajt po bajtu. Jakákoliv změna ve zpracování, byť jediné mezery, test shodí.

Zní to přísně, a taky to přísné je. Ale přesně to potřebuji. Když změním pravidlo pro konec stránky, během pár minut vidím, u kterých otisků kterých bank se změnil výsledek. Pak se podívám na rozdíl a rozhodnu se: je to oprava, nebo chyba? Pokud oprava, uložím nový výsledek. Pokud chyba, vracím se ke kódu.

Pár praktických věcí, které jsem se naučil:

  • Práce s citlivými informacemi. Potřeboval jsem si najít způsob, jak anonymizovat informace a vytvořit si otisky.
  • Jeden test pro všechno. Nemám testovací třídu pro každou banku. Mám jeden test, který projde všechny složky s otisky a ke každé ví, kterému extraktoru patří. Nový extraktor tak znamená jen přidat složku.
  • Kultura. Testy běží v češtině, protože některá metadata se formátují podle jazyka prostředí. Zní to jako drobnost — ale stačí jeden kolega s anglickým Windows a polovina testů je červená.

Dnes je v golden sadě kolem 2 700 otisků. Na slovenské straně výrazně víc než na české, protože slovenské banky mají víc variant a víc historických formátů.

Co vlastně porovnávat

Porovnat dva výsledky zní triviálně, dokud to nezkusíte. Každé zpracování PDF vrací i metadata — datum vytvoření, informace o podpisu, platnost certifikátu, verzi knihovny. Některé z těch údajů se mění při každém spuštění vyhodnocení - třeba platnost certifikátu, jiné podle toho, na jakém počítači kód běží. Kdybych je porovnával, report by byl plný rozdílů, které nic neznamenají, a ty důležité by v nich zapadly.

A tak nástroj rozlišuje, co je obsah výpisu (hlavička a transakce) a co je prostředí. Rozdíly v obsahu jsou vždycky podezřelé. Rozdíly v prostředí se ignorují, nebo se shrnou zvlášť.

A ještě jedna drobnost, která mi ušetřila hodně nervů. Když se schéma výsledku změní — přibude nová vlastnost, jiná zmizí — report to hlásí jako změnu schématu, ne jako tisíc rozdílů v datech. Jeden řádek místo tisíce.

Test jako bezpečnostní síť

Kdybych měl vybrat jedno poučení z celého projektu, bylo by to tohle: u parseru nejsou testy o pokrytí kódu, ale o pokrytí reality. Kód může mít stoprocentní pokrytí a stejně selhat na výpisu, kde banka poprvé vytiskla transakci přes dvě stránky.

Golden testy mi daly odvahu dělat velké refaktoringy. Otisky mi daly jistotu, že testuji to, co banky produkují. Díky tomu může aplikace, která dnes běží v rámci GoodVeri, měnit svoje vnitřnosti bez obav, že se to klienti dozví dřív než já.

Jak testujete aplikace, kde je vstup „cokoliv, co přijde zvenku“? Máte podobný přístup se snapshoty, nebo sázíte na něco jiného?