Pro ověření správné funkčnosti webové aplikace nám často postačí kontrola vykreslení validní stránky s požadovanými vizuálními a ovládacími prvky. Testujeme tak aplikaci z pohledu koncového uživatele, jakoby si ji sám zobrazil v prohlížeči. Ve většině aplikací můžeme nalézt místa, kde chybí dobrý objektový návrh. Pokrytí takových míst jednotkovými nebo integračními testy bývá často neefektivní z více hledisek. Takovou situaci nám mohou pomoci efektivně vyřešit akceptační testy, které nám umožní bezpečnější refactoring.

Cílem automatizovaného akceptačního testování není pouze testovat části aplikace, které jsou špatně naprogramované, ale minimalizovat nutnost uživatelského testování nebo ho soustředit na kritičtější části systému.

Nutné ingredience

Základem akceptačních testů je provádění různých kontrol nad vykreslenou stránkou. Podoba stránek může být dynamická a měnit se na základě dat v databázi. My ale potřebujeme mít jistotu, že například na stránce produktové kategorie bude minimálně jeden produkt. To vede k požadavku mít připravenou testovací databázi, která se v průběhu času nemění a při každém spuštění testu obsahuje identická data. 

Aplikace která obsahuje vždy stejná data je pouze začátek. Samotný test spočívá v tom, že se zašle požadavek na vykreslení konkrétní stránky a následně se provádí kontroly, jestli vše proběhlo v pořádku a stránka obsahuje všechny požadované komponenty. Abychom nemuseli vše dělat ručně a kontrolovat vykreslený DOM po zaslání požadavku, existují testovací frameworky, které celý tento postup automatizují  a usnadňují. Jedním z takových frameworků je například populární Codeception, který nabízí prostředky pro různé úrovně testování PHP aplikací.

Testy je nutné udržovat, aby stále procházely. Jakmile testy objeví nějakou chybu a mávneme nad tím rukou, tak počet neprocházejících testů bude narůstat až do stavu, kdy na  testy nebudeme vůbec brát ohled a přestaneme je používat. Proto je nutné pouštět testy pravidelně v rámci Continuous Integration procesu, abychom byli nuceni je udržovat. U nás k tomu používáme Travis CI, který nám hlídá coding standard, provádí statickou analýzu, spouští jednotkové a integrační testy a na závěr testy akceptační.

 

Ukázkový výsledek buildu aplikace na Travis CI

Ukázkový výsledek buildu aplikace na Travis CI

 

Každá aplikace má různé požadavky na prostředí, ve kterém poběží. Je dobré udržovat všechna prostředí (vývoj, CI server a produkce) co možná nejpodobnější (nejlépe identické), tak abychom měli všude stejné verze různých nástrojů. To nám usnadní práci při hledání chyb. Pokud například zjistíme že nám v rámci CI procesu něco neprochází, tak si budeme moci snadno ověřit u sebe, proč tomu tak je, aniž bychom byli ovlivnění různou konfigurací prostředí. 

Trendem dnešní doby, jak toho dosáhnout, je použití kontejnerového nástroje Docker. Ten pro tyto účely používáme i my (kromě produkčního prostředí).

Codeception

Jak už bylo zmíněno výše, pro akceptační testy jsme si vybrali testovací framework Codeception, který nabízí rozsáhlé možnosti testování. Od jednotkových testů až po ty akceptační.

V Codeception existují dva základní přístupy jak se kontroluje validita vykreslené stránky, využívá se k tomu buď PhpBrowser nebo WebDriver. Základním chováním PhpBrowseru je to, že pošle na zadanou stránku HTTP požadavek a parsuje zpracovanou odpověď, nespouští tedy JavaScript, za to je ale velmi rychlý. Naopak WebDriver se chová jako opravdový prohlížeč, spustí vše včetně JavaScriptu a simuluje opravdový pohyb kurzoru po obrazovce. K tomu využívá buď Selenium server nebo nějaký headless browser - prohlížeč bez grafické prezentační vrstvy, ovládaný pouze z terminálu nebo přes síť. Nevýhodou tohoto přístupu může být složitější konfigurace prostředí a znatelně nižší rychlost zpracování testů.

My jsme si pro začátek vybrali PhpBrowser, abychom se nejdříve se vším naučili pracovat a vyhnuli se některým komplikacím při použití WebDriveru. Jednotlivé akceptační testy se pak v terminologii Codeceptionu nazývají “Cest” a jak může vypadat takový test načtení domovské stránky je vidět na následujícím obrázku:

 

Test zobrazení domovské stránky
Test zobrazení domovské stránky

 

Zavoláním metody “amOnPage” frameworku řekneme, že chceme přejít na stránku s adresou “/homepage” a chceme zkontrolovat pomocí CSS selektoru, že se na stránce nachází element “#homepage-placeholder”. V podobném duchu se nesou i ostatní direktivy, které se velmi podobají zápisu anglických vět.

Implementační tipy

V začátcích jsme narazili na některé zádrhely a zároveň jsme se dostali k zajímavým vylepšením. Jedním z problémů, který jsme si nachystali sami na sebe, byla antispam ochrana nad formuláři, která kontrolovala čas strávený na stránce před odesláním formuláře. Akceptační testy ale byly natolik rychlé, že skrze tuto ochranu neprošly a museli jsme je ručně brzdit. Nakonec jsme předělali konfiguraci antispam ochrany a pro spouštění testů ji vypínáme.

K vývoji u nás využíváme Nette framework a jeho skvělou součást v podobě Tracy lišty, ta je při vývoji velmi užitečná. Pokud má ale Codeception na každé stránce zpracovat její rozsáhlou HTML strukturu, tak to značně navyšuje čas nutný ke zpracování testů. Skrytí Tracy lišty vedlo ke snížení času nutného ke zpracování testů na cca polovinu toho původního. Tracy lištu jsme chtěli pouze schovat, aby zůstal zapnutý debug mód a my jsme dostávali upozornění i na E_NOTICE. Vykreslení lišty lze ovlivnit nastavením parametru “showBar”.

Jako každý kód i testy se dají psát s horším nebo lepším návrhem. Například stejné formuláře, které se využívají ve více případech je dobré zapouzdřit do nějakého objektu. Takové objekty se nazývají Step nebo Page objekt a v dokumentaci je jejich princip hezky rozebrán tady.

Typickým Page objektem může být například přihlášení uživatele:

 

Page objekty představující přihlášení uživatele
Page objekty představující přihlášení uživatele

 

Tento objekt potom využijeme při kontrole stránky osobního profilu zákazníka, kdy před spuštěním testu nejprve provedeme jeho přihlášení:

Test zobrazení osobního profilu zákazníka

Test zobrazení osobního profilu zákazníka

 

Co nás ještě čeká?

  • vyřešit situaci, kdy doba běhu testů přesáhne únosnou mez 
  • vyzkoušet WebDriver s podporou JavaScriptu
  • zkusit jinou metodu přípravy testovacích dat a místo SQL skriptů pracovat s připravenými data fixtures

 

A jak to vše hodnotíme?

Po překonání vstupní bariéry spočívající v přípravě veškerých popsaných součástí se nám všechno to vynaložené úsilí začíná několikrát vracet. Aktualizace naších interních balíčků probíhají s mnohem větší jistotou. Stačí aktualizovat závislost a počkat až nám CI server řekne jestli je vše v pořádku. Minimalizujeme výskyt fatální chyby v produkčním prostředí, protože testujeme na nejvyšší úrovni a uživatele nevystrašíme nepříjemnou hláškou. Zároveň programátor dostává jistotu, že nerozbil jinou část systému / aplikace, na které přímo nepracoval.

Díky tomu, že už s akceptačními testy umíme správně pracovat a nezabírají nám tolik času, stávají se nedílnou součástí většiny nově vypracovaných úkolů a máme tak radost z každé úspěšně nalezené chyby, která se nedostane ven. A tato přidaná hodnota se zvyšuje s narůstajícím počtem všech testů.

Nebojte se prvotní investice, stojí to za to!
 

Diskuze