Programování řízené testy
Programování řízené testy (z anglického test-driven development (TDD), též vývoj řízený testy) je přístup k vývoji software, který je založen na malých, stále se opakujících krocích, vedoucích ke zefektivnění celého vývoje.
Prvním krokem procesu vývoje je definice funkcionality a následné napsání testu, který tuto funkcionalitu ověřuje. Poté přichází na řadu psaní kódu a nakonec úprava tohoto kódu.
Požadavky
Tato technika vyžaduje psaní automatických unit testů. Unit testy jsou takové testy, které testují nejmenší jednotku programu. Tou může být například třída (v OOP), funkce nebo metoda. Automatické testy je možné spouštět pořád dokola a opětovně testovat jednu a tu samou část programu. Automatické testy nicméně vyžadují hlubší porozumění kódu, proto bývají spíše náplní právě vývojářů než testerů, kteří testují finální program.
Vývojový cyklus
1. Napsat test
Prvním krokem při tvorbě nové komponenty je podle TDD vytvoření testu, který ověřuje, zda kód, který bude zajišťovat funkcionalitu, dělá to, co se od něj očekává. Toto první napsání testů je vlastně definicí požadavků na onu funkcionalitu. Vývojář se napsáním tohoto testu ujistí, že přesně chápe funkcionalitu a požadavky na onu testovanou komponentu, čímž se při psaní samotného kódu eliminuje odchýlení se od původního záměru a cíle. Testy mohou být psány podle use-case diagramů, user-stories, či jiných materiálů. Tento krok je odlišný od přístupů, kde se píší testy až na konci, protože nutí vývojáře zaměřit se na požadavky už před psaním kódu. Tento rozdíl se může zdát jako nevýznamný, nicméně je podstatnou odlišností.
2. Spustit testy a ujistit se, že žádný neprojde.
Poté, co jsou nové testy napsány, jsou spuštěny a všechny končí neúspěchem, protože ještě neexistuje žádný kód, který by jejich úspěšné dokončení zajistil. Tento krok funguje i jako jakási sebekontrola, která vylučuje možnost, že by nová funkcionalita byla dokončena ještě dřív, než by někdo vůbec začal s její implementací. Kdyby totiž v tomto kroku prošly jako splněné, znamenalo by to, že jsou buď špatně napsané, nebo že budou splněny vždy a ztratí tím svůj smysl.
3. Napsat vlastní kód
Po neúspěšném dokončení všech nově napsaných testů přichází na řadu psaní kódu. V tomto kroku se jedná o rychlé přírůstky, jejichž smyslem je pouze zajistit to, aby při příštím spuštění nové testy prošly. Neklade se zde za cíl, napsat hned co možná nejefektivnější a nejelegantnější kód. Efektivnost a elegance kódu je předmětem dalších kroků, zde se jedná opravdu pouze o úspěšné splnění testů.
4. Kód automatickými testy prochází
Pokud kód napsaný v minulém kroce zajistí úspěšné splnění testů, znamená to také, že plní definované požadavky. Pokud jsou testy splněné, může se přejít k poslednímu kroku.
5. Refaktorace
Posledním krokem je refaktorace kódu. Efektivita a elegance napsaného kódu je předmětem až tohoto kroku. Refaktorace kódu může probíhat i automaticky pomocí různých nástrojů. Odstraňují se duplicity v kódu a kód se celkově upravuje do co možná nejpřijatelnější podoby. Opětovné spouštění automatických testů v tomto kroku umožňuje neustále ověřovat, že zásahy do dříve napsaného kódu nezpůsobily nikde žádné chyby ve funkcionalitě a že se refaktorace nestane spíše kontraproduktivní.
Opakování
Předchozí kroky se pak dále opakují. Na základě různých vstupů (use-case diagramy, user stories, ...) je opět definována funkcionalita, která se vyjádří pomocí automatických testů, které při prvním spuštění opět neprojdou. Následně je znovu napsán kód pouze za účelem splnění testů a pokud jsou testy splněny, kód je refaktorován. Tyto přírůstky by měly být co nejmenší, přibližně 1 - 10 úprav mezi opětovným testováním. Pokud v dalších krocích skončí některý z předchozích testů neúspěchem, znamená to návrat o pár kroků zpět a změnu kódu.
Přínosy
Použití automatických testů při vývoji přináší tu výhodu, že je možné opětovné spouštění velkých množství testů, které znovu a znovu ověřují veškeré předem definované funkcionality a požadavky. Pokud nějaký zásah do kódu způsobí někde nějakou chybu, automatické testy tuto chybu odhalí.
Podobná situace nastává i při změně požadavků na dosavadní funkcionalitu. Pokud je potřeba někde něco změnit, stačí upravit nebo napsat nové testy a následně i kód. Pokud by tyto změny vedly k nefunkčnosti v jiných částech programu, opět lze snadno a rychle zjistit, co je špatně. Protože tento přístup skládá program z malých částí, je mnohem jednodušší, vypořádat se s různými vnějšími zásahy do návrhu programu.
Omezení
Omezení tohoto přístupu spočívá v tom, že v testech se mohou vyskytovat chyby stejně tak jako v kódu. Pokud jsou tyto chyby časté, může to vést k demotivaci a zanevření na tento přístup. Testy také zvyšují objem kódu, který je potřeba napsat. Zkušenosti také ukazují, že zpočátku tento přístup vede k dočasnému snížení produktivity. Omezením je také například špatná testovatelnost některých částí programů, jako například uživatelské rozhraní. Tento přístup nemůže nahradit všechny testy. Testy používané zde jsou slabé a na jejich základě nelze zapisovat například akceptační protokoly nutné pro vypuštění nebo předání programu.
Literatura
- BECK, Kent. Programování řízené testy. Praha: Grada, 2004. ISBN 8024709015.