Přejít k navigační liště

Zdroják » Různé » Testování není nástroj, ale metoda vývoje

Testování není nástroj, ale metoda vývoje

Články Různé

Stále se ještě setkáváme s názory, že jednotkové testování je práce navíc a že není, kdo by ho zaplatil. Tento článek si klade za cíl poodhalit tuto techniku vývojářům a projektovým manažerům, kteří v ni nevěří, nebo neví, že dokáže výrazně usnadnit a zkvalitnit odvedenou práci.

Pohled vývojářů a projektových manažerů je často velmi zkreslený. Testování totiž chápou špatně, jako něco navíc, něco, co sníží počet napsaných funkčních řádků kódu za hodinu a prodlouží dobu vývoje aplikace. Ze začátku se to skutečně může zdát jako zbytečná práce, na výhody ovšem narazíte při prvním refaktoringu, kdy si nevědomky rozbijete zpětnou kompatibilitu a půlka testů vám zčervená. Z důvodů, které by vás nenapadly.

Jsem toho názoru, že kód nepokrytý testy je bezcenný. Od pohledu může fungovat, ale nemusí. Algoritmus, který vypadá napsaný správně, ve skutečnosti může dělat něco jiného. Výjimka se vyvolá v nesprávné situaci. Metoda vrací něco jiného, než má. Poté, co jsem začal svůj kód testovat (a díky tomu odhalil spoustu chyb), nevěřím už ani středníku na konci řádku.

Cílovou metou při psaní testů by nemělo být 100% pokrytí kódu a ani se to tak v praxi nedělá. Vývojář by se měl v testech zaměřit na očekávané chování aplikace a ne jít slepě za spuštěním všech řádků. Psát „neprůstřelné“ a několikrát delší testy, než je samotný funkční kód, vás sice může chvíli bavit, ale je to neefektivní a po vyprchání nadšení i demotivující.

Důležitým přínosem testování je motivace a změna přístupu k práci. Náročná implementace a vymýšlení architektury se střídá se snadným a rutinním psaním testů. Ty mají vypadat tak jednoduše a čitelně, aby v nich samotných nemohla nastat chyba. Tudíž se vyhněte jakémukoli větvení kódu a cyklům a názvy testovacích metod pište natolik výmluvné (a klidně i dlouhé), aby nebylo potřeba dodatečných komentářů, které v reportu nejsou vidět.

Testování lze spojit i s nějakou time-managementovou metodou, např. GTD. Musíte přerušit aktuálně rozdělanou práci a nechcete zapomenout, u čeho jste skončili a co ještě zbývá implementovat? Dopište si na to selhávající testy (třeba i s jediným řádkem $this->fail()) – nemusíte to nosit v hlavě a při návratu hned uvidíte, kde jste minule skončili.

Zatím jsem se nesetkal s tím, že by mělo velkou váhu psát testy před samotným produkčním kódem, jak to doporučuje metodika TDD, a spoustě lidí se to může rovněž příčit. Ale je důležité, aby odevzdávaný kód byl testy pokrytý. Jak a v jakém pořadí si to vývojář na svém stroji vyřeší, je na něm. Ale přístup „testy někdy dopíšu, teď se mi do toho nechce“ je špatně. Vždyť při samotném psaní produkčního kódu určitě testujete, jen takové testy nemají stálý charakter. Dumpujete si proměnné, zkoušíte na nějakém dočasném kódu (třeba ve funkci main() nebo v controlleru), jestli daná třída dělá to, co má. Jednotkové testy zavádějí stálost. Na jedno kliknutí prověříte funkčnost všeho dosavadního kódu.

Úplně nový význam to nabírá, pokud vyvíjíte webovou aplikaci a potřebujete zjistit, zdali jste např. refaktoringem modelu nevyřadili z provozu některé sekce webu. Bez testů by ověřování funkčnosti trvalo několik minut (pokaždé) a musel by ho provádět člověk, jehož práce stojí peníze. Pokud ovšem jednotkovými testy vhodně testujete controllery, máte funkčnost aplikace ověřenou i z hlediska uživatele.

Samozřejmě že testy nejsou všespásné a neodhalí všechny problémy. Pokud přijdete na chybu, ať už pohledem do zdrojového kódu anebo při jeho používání, prvním krokem by mělo být napsání testu, který danou chybu reprodukuje a ověření, že test skutečně selhává. Po její opravě a úspěšném průchodu testem získáte jistotu, že se daná chyba nevrátí, protože máte kód, který ji dokázal vyvolat a který opakovaně testuje, jestli se znovu neobjevila.

Testy mohou být zajímavé i pro projektového manažera, který podle nich může rychle zjišťovat, co tým udělal – co není otestované, tak ho nezajímá, protože to nemusí fungovat. Pokud vyžaduje nějakou další funkcionalitu, která závisí třeba i jen na implementačním detailu, její výsledek by měl být navenek poznat, aby byl otestovatelný. Prvním krokem by mělo být opět napsání selhávajícího testu a přiřazení úkolu vývojáři.

Mnohokrát se v praxi setkáme s názory, že na testování lidé nemají čas. Pokud honíte deadliny a sotva stíháte odevzdávat práci, je jasné, že na unit testy už ve vašem rozvrhu není místo (a nejspíš vám ani o kvalitu nejde). Ale vy, kdo to se svou prací myslíte vážně a chcete ji odvádět kvalitně, zkuste testování včlenit do vývoje jako jeho nedílnou součást, ta investice se vám mnohonásobně vrátí. Stačí začít!

Komentáře

Subscribe
Upozornit na
guest
28 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
na1k

Nechystá se článek o tom, jak s testováním v PHP začít? Mám zkušenosti s testováním v Javě (JUnit), ale v PHP mi to vždycky přijde dost složité.
Myšlenkově se vždycky zastavím na nějakém problému (např. jak v Nette testovat správnou odezvu presenteru? tím jaké proměnné předá šabloně? něčím jiným?) a do praxe už to neuvedu.

pavsyk

Mně osobně se sice z nějakého iracinálního důvodu také příči psát testy před produkčním kódem, ale to úvodní napsání testu a jeho spuštění má svůj význam. Je to vlastně „otestování testu“ – správný výsledek je, že musí selhat. Zmenší se tím riziko, že v testu je chyba, která dává falešný pozitivní výsledek.

Riny

Hele, to je hodně zajímavá myšlenka ^^. Asi to bude důvod, proč je začnu psát před produkčním kódem :3.

pk

pokud nemate pevne dane API, ktere mate naimplementovat, tak vytvoreni testu vam pomuze si ohledne toho API ledacos ujasnit.

uf

Taky jsem chtel pripsat, ze pouziti vasich trid v testu vlastne vytribi API. Napr. si clovek uvedomi, ze musi predat nejake dalsi infórmace zvenku.

Riny

Jn, taky hezká pointa. Tohle by jsme se měli taky učit ve škole, takto se k tomu dostanou lidi až v praxi až se spálí (pokud nebudou mít štěstí na dobrého team leadra) nebo pokud se o programování zajímají aktivně.
Jakože dělali jsme nějaké drobné JUnit testy, ale osobně si myslím, že tomu byla přiložena minimální váha až už vůbec nebyly zmíněny tyto výhody…

jos

ano, návrh PHPUnit není moc dobrej, je na čase (pro odbourání demotivace) začít používat něco jinýho (http://www.testilence.org/)

test:

class whateverTest
extends Tence_TestCase
{
    public function testOK()
    {
        return $this->assertTrue(true);
    }
    public function testFailure()
    {
        return $this->assertTrue(false);
    }
    public function testMalformed()
    {
    }
}

spuštění testu

$ make check SUITE=whateverTest
cd tests && 
  tence -I "$PWD/..:$PWD/../.." -r alltests.php whateverTest
.FM
whateverTest::testFailure
 AssertEquals expected boolean(True) got boolean(False)
whateverTest::testMalformed
 bad test return value: type NULL, value NULL

3 run, 1 failed, 0 threw, 1 malformed
make: *** [check] Error 5

sorry za to formátování, v náhledu nevidim že by fungoval tag code, tak sem to dal do pre

František Kučera

Ad „na výhody ovšem narazíte při prvním refaktoringu, kdy si nevědomky rozbijete zpětnou kompatibilitu a půlka testů vám zčervená. Z důvodů, které by vás nenapadly.“

Nic proti testování, ale v první řadě je potřeba navrhovat strukturu systému tak, aby k takovým situacím nedocházelo – nesmí to být černá skříňka, která si dělá co chce, změna jednoho modulu/metody ovlivní celý systém atd. I složité systémy lze strukturovat tak, aby byly přehledné – aby to nebylo klubko zamotaných „špaget“, kde všechno souvisí se vším. Takže doporučuji navrhovat systém tak, abychom se v něm vyznali a aby nám nespadl na hlavu, i kdybychom žádné testy neměli. Testy nám potom dodají jistotu a dodatečnou kontrolu (což samozřejmě neznamená, že je nemůžeme napsat před samotným funkčním kódem, ale píšeme je po analýze, návrhu).

Ad „Jsem toho názoru, že kód nepokrytý testy je bezcenný.“

Příliš silná slova. Všechno je o penězích a vážení rizika. S rostoucími investicemi do testování zvyšujeme kvalitu kódu, ale efektivita každé další koruny investované do testování se postupně snižuje. V první fázi investujeme do testování trochu času (peněz) a odhalíme zásadní chyby, které by vedli k neakceptaci programu nebo drahému selhání, další investicí do testování objevíme nějaké kosmetické chyby, což se asi taky vyplatí… testovat můžeme dál a dál, do aleluja, ale už z toho nic nebude – budeme objevovat banální chyby, které za tu námahu (čas/peníze za testování) nestojí – daleko ekonomičtější je je tam nechat a opravit je za chodu nebo v další iteraci. Jejich testování by znamenalo vyšší náklady než výnosy (snížené riziko/ztrátu). Kód nepokrytý testy tedy není bezcenný – pokud za něj zákazník zaplatí, cenu má, a pokud bude fungovat.

Ad „Bez testů by ověřování funkčnosti trvalo několik minut (pokaždé) a musel by ho provádět člověk, jehož práce stojí peníze“

Autor neslyšel o automatizovaných testech funkčnosti? Ty jsou snad ještě důležitější než jednotkové testy, protože kontrolují funkčnost programu z pohledu uživatele – komplexně – ne jen jestli nějaké malé kousíčky uvnitř fungují správně (to je předpoklad nutný, ale ne dostačující).

Ad „potřebujete zjistit, zdali jste např. refaktoringem modelu nevyřadili z provozu některé sekce webu.“

Zde se hodí silně typované statické jazyky – ne že by u nich testy nebyly potřeba, ale jejich význam není tak velký.

Ad „Testy mohou být zajímavé i pro projektového manažera, který podle nich může rychle zjišťovat, co tým udělal – co není otestované, tak ho nezajímá, protože to nemusí fungovat.“

Projekťák nepozná, jestli ty testy jsou správně napsané, nebo jestli to jsou jen jako-testy, aby tam byly zelené fajfky a všichni byli spokojení.

drevolution

„Nic proti testování, ale v první řadě je potřeba navrhovat strukturu systému tak, aby k takovým situacím nedocházelo“

Franto, ono k tomu stejně dřív nebo později dojde a pak ty testy vyvažuješ titanem :) Je dobře, že jsi zmínil i další aspekt, který má na kvalitu kódu vliv, ale o tom Ondra nepsal.
Refaktoring se prostě dělá. Některé týmy (můžeme jim třeba říkat že jsou to ty agilnější :-)) ho dokonce dělají relativně často. A refaktoring bez unit testů v projektu, který už má za sebou pár měsíců vývoje, to je jako hraní Jengy.

„Projekťák nepozná, jestli ty testy jsou správně napsané, nebo jestli to jsou jen jako-testy, aby tam byly zelené fajfky a všichni byli spokojení.“

Vždy záleží na tom, jak moc je daný projekťák technicky zdatný. Projektový manažeři se občas rekrutují z řad senior programátorů či týmových vedoucích, takže by se jistě dalo souhlasit s tím, že „testy *mohou* být zajímavé i pro projektového manažera“.

Jakub

…Autor neslyšel o automatizovaných testech funkčnosti? Ty jsou snad ještě důležitější než jednotkové testy, protože kontrolují funkčnost programu z pohledu uživatele…

Mno a není to v zásadě to stejné? Nezáleží na tom jestli je na prvním místě PHPunit nebo Selenium důležité je, aby byly testy při vývoji webů samozřejmostí (což nyní neplatí :-().

Břetislav Wajtr

RE: odstavecek o snizujicim se vyznamu testu v case, hlavne veta „daleko ekonomičtější je je tam nechat a opravit je za chodu nebo v další iteraci“.:
S tim si dovolim nesouhlasit, testy maji stejny vyznam po celou dobu existence projektu – pravda, ze zacatku jejich vyznam spociva spise v overovani vyvoje, ale postupne je velka sada testu pomalu jedinym moznym zdrojem informace, jestli jsme svoji byt malou zmenou „neco nerozbili“. A pokud je pro nas kriticky dulezite „nic nerozbit“ a presto pokracovat ve vyvoji, pak automaticke testy dramaticky nabyvaji na dulezitosti. A k vete „daleko ekonomičtější je je tam nechat a opravit je za chodu nebo v další iteraci“ – vim, ze nasl. priklad je trochu prehnany, ale predstavte si, ze vyvyjite software pro letadla a diky male chybce to letadlo spadne a vsichni zahynou. Lidi na palube toho letadla asi nebude moc zajimat, ze tu chybu v dalsi iteraci opravite :).
Po nekolika letech vyvoje naseho projektu jsem nedavno diky automatickym testum objevil chyby, ktere se rozhodne nedaji oznacit za banalni a kdyby se projevily u zakaznika, byl by to p..ser. A byly tam jenom proto, ze projekt uz je priliz velky na to, abychom ho dokonale udrzeli v hlavach a domysleli vsechny scenare…

František Kučera

Zkusím to vysvětlit jinak… Existuje dokonalý software?

…neexistuje – každý software má chyby, vždycky je co vylepšovat, jsme jenom lidé. Cílem řízení kvality (něco víc než testování) není dotáhnout ten software k dokonalosti, snížit počet chyb na nulu, ale dotáhnout ten software do přijatelné kvality za přijatelnou cenu. Tzn. aby letadla nepadala (to je nepřijatelné), ale zároveň aby vývoj nestál miliardy a netrval desítky let (což je rovněž nepřijatelné). Proto je správné některé drobné* chyby (nedokonalosti) v programu nechat a neztrácet s nimi čas (ani s jejich testováním) a opravit je buď později nebo až je bude někdo potřebovat vyřešit.

*) drobná chyba je taková, která nezpůsobuje škody typu pád letadla, smrt lidí, finanční ztráty… nezpůsobuje škody prakticky žádné, akorát může způsobit třeba trochu nepohodlí při používání programu – v malém procentu případů atd.

uf

Dovoluji si oponovat: Souhlasím s názorem z knihy Programátor pragmatik – Opravujte rozbitá okna. Najdete-li někde něco rozbitého, nedodělaného, opravte to hned. Jinak se vám to nakupí. Ona i malá chybka, která jen způsobí nepohodlí uživatele, může skrývat něco hlubšíh.

Jestli sledujete Minuty před katastrofou, tak se při každe havárii sejde několik drobností, opoměnutí, nedorozumění, nepochopení a předpokladů a vede to k chybě.

Proto třeba tento týden budu prověřovat rodné číslo v našem systému (viz http://www.aspectworks.com/cs/blog/2010/05/generator-rodnych-cisel/ a odkazy z článku).

pas

To přece není v rozporu. Ano, malá chyba může vést ke katastrofě, ale musím odhadnout, s jakou pravděpodobností, a pak je to zase jen ta ekonomie. Samozřejmě si vždycky u reportážích o leteckých katastrofách říkám, jak by to bylo fajn, kdybych po každém pádu mojí aplikace dostal tým lidí a milion dolarů na zjištění příčiny a přijetí opatření do budoucna. :)

Rychta

Zajimalo by me jestli ma cenu a pripadne jak testovat rozhrani? Ma vubec cenu ho testovat, kdyz si udelam MOCK rozhrani a pak nastavim na metodu->will($this->returnValue(…)) a otestuji vracenou metodu.

Villlém

Samotné interface je zbytečné testovat … ani není co, ale ke každému rozhraní se váže nějaký kontrakt, který „musí“ plnit každý implementátor rozhraní. No a tento kontrakt lze otestovat. Takováto sada testů se pak může pustit na každého implementátora.

Aleš Roubíček

Testovat má cenu pouze výkonný kód. Rozhraní je jen předpis. Stejně tak je zcela zbytečné testovat vlastnosti objektu (settery a gettery). Mock objekty jsou dobré pouze pro testování objektu v izolaci. Testování mock objektu samotného je opět zbytečnost. Proč testovat něco, co nepřináší žádný užitek?

Mastodont

Vždyť při samotném psaní produkčního kódu určitě testujete, jen takové testy nemají stálý charakter. Dumpujete si proměnné, zkoušíte na nějakém dočasném kódu (třeba ve funkci main() nebo v controlleru), jestli daná třída dělá to, co má. Jednotkové testy zavádějí stálost. Na jedno kliknutí prověříte funkčnost všeho dosavadního kódu.

S tímhle mám velký problém, ty první testy samozřejmě dělám, jednotkové ne. Tou stálostí se ale rozumí spíš dokumentovanost. Dočasný kód člověk neukládá, takže jím nemůže argumentovat. Bohužel se unit testy budu muset naučit, protože bez nich to dnes „nejde“ – i když drtivá většina těchto testů předváděná v různých tutorialech kontroluje úplné triviality, které jsou stejně jasné z kódu :-(((

jos

tohle píšu z pozice PHP programátora

až ti testování úplných trivialit ušetří spoustu času (takže zachrání termín) při hledání překlepů (protože s unittestama překlepy neexistují) nebo umožní dělat brutální refaktoringy bez refreshování desítek tabů v prohlížeči, tak unittestování teprve doceníš

přístup typu

cože? to mam testovat že mi metoda sečte dvě čísla?

se pak rychle obrátí v přístup

cože? na tenhle kód nejsou testy, když tomu nic nebrání?

wdolek

nechci vypadat jako nejakej über ignorant, ale me se to stejne stale zda takove… „prapodivne“. uz sem si nekolikrat pohraval s myslenkou, ze ty testy udelam ;) , ale stale se k tomu nemuzu dokopat.
ono je to pekne podivat se tady na par tutorialu (viz clanek k Nette), ale testovat jestli mam v databazi 2 zaznamy mi prijde naprosto k nicemu – dulezite je snad co to je zac, k cemu se to vztahuje, jestli jsou spravne vlozene data* a podobne. napsani takovych testu by pak skutecne znamenalo stravit jejich psanim delsi cas, nez psanim samotne aplikace.

* nedavno jsem narazil na jakousi „chybu“ TinyMCE – nekolik hodin sem koukal do zdrojaku, kde se mi ztraci hodnota z formulare. nakonec jsem zkusil vypnout TinyMCE – ktere je samozrejme az na frontendu uzivatele – a voala, cely problem zpusobovalo prave to, ze z nejakeho duvodu ve vsech formularich aplikace, az na tento jeden, TinyMCE nepredal svuj obsah zpet textovemu poli. jak testovat takovehle veci? (tedy – proc delat unit testy, kdyz pak stejne musi prijit tester a cele to ozkouset)

drevolution

„dulezite je snad co to je zac, k cemu se to vztahuje, jestli jsou spravne vlozene data* a podobne. napsani takovych testu by pak skutecne znamenalo stravit jejich psanim delsi cas, nez psanim samotne aplikace.“

Z počátku to možná půjde pomaleji, ale stejně jako se vším, se s s tím začneš sžívat a brzo budeš psát testy několikrát rychleji, než na začátku. Pak se podíváš zpět a zjistíš, že na tom vlastně moc není a že jsi rád, že jsi se k tomu konečně dokopal.

jos

test kterej leze do databáze není unit test (Beck, TDD by Example)

testování kooperace browseru s aplikací pak už ani náhodou (takový testy samozřejmě nezavrhuju, ale to je jiná hra na jiným hřišti, v jiný lize)

na pár tutoriálů se vykašli, přečti si toho Becka, a až budeš vědět co je TDD a napíšeš si pár testů*, tak tě to über ignorantství přejde

*) v tvým případě by to chtělo testovat: když mi přilezou správně data, pokusí se je aplikace správně nacpat do databáze? potom při úvahách kde se stala chyba můžeš na základě testů vyloučit některý místa, kde se to „taky mohlo podělat“, ale nepodělalo, protože testy procházejí

uf

Predstavte si, ze delate ve stare technologii a musite testovat rucickama. TO me vzdycky s..tvalo. a nehnu s tim

jos

radikální řešení: najdi si jinou práci (teda jinde)

uf

Pracuje se na tom, ale hochu, ja nejsem v Praze

Naith

A máš možnost kód krokovat, zadat break-points a vypsat stav proměnných?

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.