Test-Driven Development — programování řízené testy

Chaos je všude

O chaosu je známo, že se vyskytuje všude a v tomto ohledu není výjimkou ani vývoj software. Od samotného počátku, co lidé vytvářejí počítačové programy, existují snahy o ovládnutí chaosu s cílem učinit z vývoje software předvídatelný proces. S rostoucím využitím informačních technologií ve všech oblastech lidské činnosti neustále rostly nároky na funkčnost a kvalitu software, který v důsledku nabýval na velikosti a složitosti, a softwarové projekty přestaly být zvladatelné.

Snaha o nastolení řádu vedla k formulování různých metodik vývoje software, což si lze představit jako souhrn pravidel a postupů, kterými bychom se měli řídit, pokud chceme vývoj programu dotáhnout do úspěšného konce. Existují různé metodiky vývoje software, lišící se složitostí a způsobem řízení vývoje, od neformálních (agilních) až po podrobně strukturované (normativní).

Nejpopulárnějšími metodami vývoje software posledních let jsou bezesporu agilní metody vývoje software. Asi nejznámější z nich je extrémní programování. Klíčovou součástí extrémního programování je i technika vývoje řízeného testy (TDD). Ačkoli obliba extrémního programování jako celku postupně upadá, princip vývoje řízeného testy má šanci udržet se na výsluní delší dobu. Techniku vývoje řízeného testy bych vám chtěl představit v následujících řádcích.

Testování

Klasický životní cyklus vývoje software je rozdělen těchto do fází:

V mnoha případech se jedná o zdlouhavý a nákladný proces a nalezení defektů během pozdních fází vývoje může mít fatální následky pro celý projekt. Aby se vývojáři vyvarovali takových chyb, je nutné, aby měli možnost průběžné kontroly, zda se neodchýlili od požadavků na výsledný produkt.

Jednu z možností jak si ověřit, že systém dělá to, co chceme, nabízí testy. Test si lze představit jako sadu podnětů a očekávaných odezev systému. Při testování ověřujeme, že program se chová korektně — pro dané vstupy vrací správné výstupy. Po proběhnutí testu bychom měli obdržet jednoznačnou odpověď (úspěch/neúspěch).

Základní druhy testů

Jako první měřítko rozdělení je způsob, jakým se testy provádějí. Podle tohoto měřítka lze testy rozdělit na automatizované a manuální. Popularita testování vzrostla hlavně díky vývoji nástrojů, které umožňují jednoduchý vývoj automatizovaných testů a jejich spouštění ve velkém měřítku. Vývojář má tak možnost si opakovaně ověřit, že aplikace splňuje požadavky dané testy, během chvíle a často stiskem jednoho tlačítka.

Druhé hledisko rozdělení je podle části systému, kterou testujeme. Prvním a nejjemnějším druhem testu je test jednotky (unit-test). Jednotka je nejmenší částí systému. Různí se názory na to, co lze považovat za jednotku systému. Pro objektově orientované programy to může být buď třída, nebo metoda. Další druh testu se nazývá funkční test. Funkční test se používá pro testování větších částí systému (modulů) a pohlíží na systém zvenku — jeho zájmem není vnitřní implementace testovaných operací (black box). Posledním druhem testu je test integrační, který testuje součinnost systému jako celku.

Představení programování řízeného testy

Test-last versus test-first přístup

Tradiční přístupy vývoje předpokládají existenci kódu programu, předtím, než bude možné testovat a vytvořené testy využívají pouze pro účely kontroly, zda se projekt neodchýlil od zadání. V odborné literatuře se tento způsob označuje jako test-last.

Naopak při programování řízeném testy (TDD), vytváříme testy předtím, než máme dostatek kódu, který by testy prošel (test-first přístup). Účel vytváření testů v TDD není kontrola, zda kód souhlasí se specifikací, ale testy zde představují nástroj pro návrh systému. Ačkoliv se to nezdá, kořeny test-first přístupu, lze nalézt i, z pohledu IT, v dnes již vzdálené minulosti. Některé modely životního cyklu software z 80. let 20. století zahrnovaly testování v počáteční fázi projektu a některé zdroje tvrdí, že prvky TDD použila americká Národní agentura pro letectví a kosmonautiku (NASA) v projektu Mercury již v 50. letech 20. století.

Mnoho vývojářů používá test-first přístup aniž by si to uvědomovali. Kent Beck, popularizátor extrémního programování a TDD, sám tvrdí, že test-first přístup se naučil již v mládí, při čtení knihy o programování. Kniha radila stanovit si nejdříve vstup programu a k němu určit očekávaný výstup. Potom bylo třeba programovat tak dlouho, dokud program neposkytoval očekávané výstupy.

Refaktorování

Refaktorování je další významnou technikou, používanou při agilních formách vývoje. Cílem refaktorování je čistý kód, který funguje. Refaktorování je úprava zdrojového kódu systému po malých izolovaných změnách, které nemají za následek změnu funkčnosti. Zachování funkčnosti lze během refaktorování kontrolovat opakovaným spouštěním testů. Refaktorování může výrazně zlepšit čitelnost kódu, odstraní duplicity a usnadní tak budoucí údržbu a rozšiřování systému. Protože se jedná o malé definované a kontrolované změny, lze je provádět i automatizovaně pomocí nástrojů pro refaktorování, dnes již integrovaných do mnoha populárních vývojových prostředí, což výrazně zvyšuje produktivitu vývojáře. Základní katalog úprav — refaktorizací lze nalézt ve výborné knize s názvem Refactoring od Martina Fowlera.

Červená, zelená, refaktorování

Princip práce při programování řízeném testy, vyoobrazený na obrázku č. 1, shrnuje Kent Beck do tohoto dobře zapamatovatelného sousloví: červená, zelená, refaktorování. Názvy barev v tomto sousloví mají souvislost s uživatelským rozhraním populárního nástroje pro automatizované spouštění testů, JUnit, kde červený proužek znamená, že test selhal a naopak zelený svědčí o úspěšnosti provedení testu. Popišme si tedy základní kroky podrobněji:

  1. Napište test, napoprvé je jasné, že test určitě selže nebo nepůjde vůbec zkompilovat.
  2. Rychle implementujte testovanou logiku tak, aby test proběhnul.
  3. Pomocí refaktorování a opakovaného spouštění testu upravte kód do přijatelné podoby.

Tato trojice je alfou a omegou programování řízeného testy. Z tohoto také plyne rovnice programování řízené testy = test-first přístup + refaktorování.

Aktivity při vývoji řízeném testy.
Obrázek 1: Vývoj řízený testy

Testování obnovuje sebedůvěru

TDD je, spíše než způsob testování, programovací technika s vedlejším efektem, který zaručuje, že veškerý kód je řádně pokryt testy jednotek (unit-testy). Pro kompletní testování je třeba vzít v úvahu ještě funční a integrační testy.

Tradiční testování, pokud je úspěšné, vede k odhalení defektů. V TDD je to stejné, pokud test selže, jedná se o pokrok, protože víme, kde je třeba vyřešit problém. Důležitější je, že můžeme brát za jasný znak úspěchu, pokud test po opravení defektu již nikdy neselže. TDD zvyšuje důvěru v to, že systém funguje správně a odpovídá požadavkům, čímž dodává vývojáři odvahu vrhnout se do dalších změn bez obav, že nové změny způsobí selhání systému. Pokud nové změny způsobí defekt, bude odhalen brzy díky testům.

Zhodnocení

Vývoj řízený testy je technika, která je v současné době hojně využívaná a její obliba roste. Důvod její obliby tkví ve faktu, že úsilí nutné k jejímu osvojení není tak veliké, jako u extrémního programování, jehož je TDD součástí. Vývojář sice musí mít z počátku disciplínu k tomu, aby testy opravdu psal a spouštěl, ale bez toho by se nejednalo o programování řízené testy. Díky jejímu charakteru, je možné její použití v kombinaci s různými technikami vývoje na nižší úrovni (např. v rámci jedné iterace) a i ve větším spektru projektů. Programování řízené testy mohu všem vřele doporučit.

Literatura

  1. David Janzen, Hossein Saiedian: Test-Driven Development: Concepts, Taxonomy and Future direction.
  2. Scott W. Amber: Introduction to Test Driven Development (TDD).
  3. Kent Beck: Programování řízené testy. Grada, 2004.