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

Zdroják » Různé » Ještě k testování

Ještě k testování

Články Různé

SEO, MVC, návrhové vzory, knihovny a AJAX už všichni umí, nebo jsou o tom alespoň přesvědčeni. O použitelnosti má ponětí stále víc vývojářů. Kdekdo se zaklíná „čistým kódem“… Jen jedna věc vzbuzuje zatím stále silný odpor – testování! Racionálně vzato to nedává smysl, takže příčina bude někde jinde…

S automatizovaným testováním kódu (a ve zbytku článku budu mít na mysli právě to) jsem se setkal v několika firmách. Nikde ho nedělali. Když jsem se ptal proč, dozvěděl jsem se vždy nějakou variaci na starý příběh o testování.

Starý příběh o testování

U nás ve firmě jsme vždycky psali kód tak, jak jsme uměli nejlíp. Postupně jsme se naučili pracovat s CVS a s knihovnami kódu a když byl čas, a že skoro nikdy nebyl, tak jsme zkoušeli i novinky. Mladý zapálený programátor nám jednou říkal, co se dozvěděl o Agile, jako že tam dělají ty scrumy a iterace a že programujou dva najednou, no to jsme se zasmáli, to jsou nesmysly, ale něco z toho jsme si vzali – zavedli jsme podle toho scrumu každodenní ranní porady.

No a tenhle vendelín jednou taky přišel s tím testováním. Já programuju patnáct let, takže nějaké zkušenosti mám. Od začátku mi bylo jasný, že to je spousta práce navíc, kterou nám nikdo nezaplatí. Kluci budou hodinu psát třídu a dvě hodiny test – jako k čemu to je? No, ale všichni to chválej, tak na tom asi něco bude, tak jsme to v létě, když bylo volnějc, zkusili. U jednoho takovýho projektu, co jsme dělali, jsme začali psát ke každý třídě testovací skripty.

Byl to šílenej vopich, kluci nadávali, že mají dvakrát tolik práce, že by za tu dobu byli už hotoví s celým projektem, a že je to jen zdržuje. Pár chyb to našlo, to sice jo, ale žádná sláva, na tu spoustu práce, co jsme s tím měli… Navíc to třeba vůbec nenašlo jasný chyby, co jsi v tom kódu viděl jen kdyžs ho přečetl! A nejhorší bylo, že u malých tříd to bylo OK, ale když jsme to dali dohromady a pustili proti databázi, tak se třeba ukázalo, že to vůbec nefunguje – a přitom ty unit testy byly všechny OK, OK, OK… Takovýhle testování je naprd. Navíc pak přišly nějaký změny a ty testy bysme museli stejně přepisovat, a to by se nám už vůbec nevyplatilo, udržovat dvojí kód, takže u nás jednoznačně #fail.

Vono teoreticky to zní hezky a pro takový ty malý třídy, kde se něco počítá, je to možná dobrý, ale v praxi to je k ničemu… Jediný testování, který má smysl, je to, že si každý zkusí, jestli to, co napsal, taky funguje. Takhle to dělají programátoři odjakživa a šlape to.

Inu, v praxi je k ničemu každý pracovní postup, který aplikujete mechanicky, bez pochopení jeho podstaty (taková kargokultická metodika). Vzít si z agile jen „ranní porady“ je nejjistější způsob, jak zjistit, že „to nefunguje“.

Ruku na srdce – kolikrát se vám stalo, že jste o něčem prohlásili, že to je „naprosto na houby“, až vám jednoho dne někdo ukázal, jak to používat, a vy jste museli uznat, že nástroj je výborný a „na houby“ bylo hlavně to, že jste s ním neuměli nebo nechápali, k čemu je? Mně mockrát.

V pozadí mnohých sporů a odmítání je leckdy nepochopení. Dovolte mi, abych byl tedy chvíli „advokátem pro testování“; mým cílem není přesvědčit vás v článku o tom, že byste měli testovat a že se vám to vyplatí, ale zkusit vyviklat některé protiargumenty, v jejichž základu je právě nepochopení. Čímž neříkám, že můj pohled na testování je jediný správný (to ale nedělají ani advokáti; místo toho to nazývají „právní názor“).

Zvolený obor

Testování je velmi široká oblast a mnoha lidem splývá, proto než se pustím do obhajoby, musím nejprve vymezit oblast, které se bude obhajoba týkat. Rád bych se věnoval jednotkovým (unit) testům. Jsou pravděpodobně nejznámější, nejčastěji vyjmenovávané, ale na druhou stranu hodně specifické.

Jednotkové testy jsou automatizované postupy pro otestování jednotky kódu (třída, knihovna, unit, skript, … – tedy něco, co lze samostatně testovat). Jejich cílem je strojově otestovat, zda daná jednotka dělá to, co dělat má, a zda nedělá něco, co dělat nemá. Je jasné, že automaticky můžeme otestovat pouze to, co se automaticky otestovat dá, resp. co lze automaticky otestovat snadno.

Automatizované testování nenahrazuje ruční; doplňuje ho.

U jednotek testujeme, zda:

  1. vrací správné hodnoty na správné vstupní údaje
  2. vrací správné hodnoty na mezní vstupní údaje
  3. legitimně zhavaruje tehdy, když zhavarovat má

Co to znamená? U jednoduchých funkcí zadáváme vstupní hodnoty a kontrolujeme výstupní, resp. chování funkce. U složitějších testujeme to, co testovat lze. Kupříkladu u třídy, která bude generovat CAPTCHA obrázek, nebudeme psát OCR, který bude vyhodnocovat, zda výsledek opravdu obsahuje požadované znaky, to je extremistický nesmysl. Otestujeme, zda při zadání dobrých vstupních údajů vygeneruje třída obrázek, jestli ten obrázek má patřičné rozměry a patřičný formát. To je snadné otestovat. To, jestli obrázek obsahuje opravdu daný text daným fontem, už nebudeme řešit unit testem; ověříme to metodou „kouknu a vidím“.

Ne každé testování je automatizované; ne každé automatizované testování je unit test.

Jednotkové testy by měly v ideálním případě otestovat každou metodu třídy, každou funkci v knihovně, každý řádek kódu, navíc takovým způsobem, který je nezávislý na zbytku systému či na vnitřních stavech. Každý „testovací případ“ by měl pracovat s čistou kopií jednotky.

Pokud jednotka používá nějaké komplexní funkce „zvenčí“, pak pro testování podstrčíme „mock object“, který se bude navenek tvářit tak, že opravdu funguje, ve skutečnosti ale jen vrátí testovací data. Řekněme, že budeme testovat HTML generátor, který generuje stránky ze záznamů v databázi. Namísto objektu, který přebírá data z databáze, podstrčíme „mock“ – jednoduchou třídu, která má stejné rozhraní, ale na getTextById() vrátí testovací „Lorem ipsum“. Jednotkové testy tak proběhnou nezávisle na okolí.

Unit testy nezjistí, jestli celý dům bude stát. Testujeme jednotlivé cihly, maltu, tvárnice, tedy základní stavební prvky, a ověřujeme, jestli fungují tak, jak od nich očekáváme.

Jednotkovými testy netestujeme, zda jednotka funguje spolu s ostatními; od toho jsou integrační testy. Netestujeme jimi ani to, jestli celá aplikace funguje. Očekávat, že jednotka pro generování HTML funguje, a tím pádem musí fungovat celý web, je bláhové. V dalším textu se nebudeme zabývat ani integračními testy, ani testováním aplikace, zůstaneme jen u automatizovaných jednotkových tes­tů.

ISO9001

K čemu nám tedy takové testování je? Nezjistíme tím, jestli to spolupracuje se zbytkem aplikace, nezjistíme, jestli aplikace funguje… Automatizované unit testy mají jinou hodnotu: jsou automatické (můžou tedy běžet bez zásahu člověka, např. na serveru jako hook u verzovacího nástroje), opakovatelné a jejich výsledky lze dobře zpracovat.

Trochu to připomíná známou (a mnohými proklínanou) normu ISO9001. Tato norma nezajišťuje, jak si mnozí lidé myslí, jakost výrobků. Tato norma je zaměřena na to, aby veškeré procesy byly jasně popsané, specifikované a opakovatelné. ISO9001 vám nezaručí, že při výrobě neuděláte chybu. Postup podle této normy pouze zaručí, že chybu uděláte vždy stejně (pokud je procesní), nebo že zjistíte, kde vzniká, protože jednotlivé kroky jsou přesně popsané. Ano, je to opruz, popisovat přesně všechny procesy, sepisovat lejstra o tom, co se dělá a jak se to přesně dělá. Ale když je někde chyba, můžete se postupů popsaných v lejstrech při hledání držet. Buď zjistíte, že někdo postup nedodržel, nebo že je v procesu chyba – a pak ji můžete opravit a popsat proces znovu.

S testováním je to podobné. Test není vaše ověření, že vše funguje; na to by byl leckdy opravdu drahý. Test je nástroj pro dlouhodobou udržitelnost kódu a pro rozumnou práci s ním. Dobře napsané testy dokáží odhalit problémy při zásahu do kódu. Většinu situací „tady přepíšu pár řádků, bude to ale fungovat stejně“, které vedou k prapodivným chybám, můžete s jednotkovými testy zachytit dřív, než si zavlečete do kódu skryté chyby.

Test je tak dobrý, jako jeho autor

Testování je jako španělská hospoda – najdete tam jen to, co si s sebou přinesete. Žádný test neobjeví v kódu nic, co autor nedokáže popsat. Myslet si, že unit test objeví chybu tam, kde nikoho nenapadlo, že by mohla být, je naivní.

Napsat dobrý test je trošku umění, především proto, že mnozí lidé postupují při ověřování chybně. Lidský mozek má tendenci hledat případy, které naši teorii potvrzují, namísto toho, aby hledal případy, které by jí vyvracely, kdyby fungovaly. Jinými slovy: musíme testovat nejen správnou funkčnost, ale i správnou nefunkčnost. 

Najít ale všelijaké kombinace, které by měly zhavarovat, vyžaduje opravdu zkušeného programátora s dobrou fantazií. Taky nikdo netvrdí, že napsat dobré testy je hračka!

Jednotkové testování není všespásné

Myslet si, že napíšu jednotkový test a knihovna bude automaticky dobrá a použitelná je bláhové. Myslet si, že jednotkový test zaručí kvalitní kód, je taky nesmysl. Přesto mnozí očekávají od jednotkových testů něco, co jim jednotkové testy nemohou nabídnout, a jsou pak rozčarováni z toho, že jejich očekávání nebylo naplněno. Často pak z neúspěchu viní testování jako takové.

Zopakujme si ještě jednou: Jednotkové testy slouží k automatizovanému, opakovatelnému a strojově zpracovatelnému testování izolovaných funkcí. Není to nástroj pro zajištění kvality nebo vhodnosti pro daný účel; nenahradí to dobrou analýzu ani dobrý návrh. Použijete je hlavně při dlouhodobé údržbě vlastního kódu. Naprosto neocenitelné jsou jejich služby ve chvíli, kdy napíšete „verzi 2“, která „by měla být kompatibilní s verzí 1“. Máte-li „verzi 1“ pokrytou dobrými testy, uvidíte na první pohled, jak to s tou kompatibilitou ve skutečnosti je.

Pokud píšete kód vždy důsledně jen na jedno použití, nasadíte ho do aplikace a pak už se k němu nikdy nevrátíte, tak pravděpodobně tuhle výhodu neoceníte. Po pravdě řečeno v takovém případě máte hlavně úplně jiný problém než to, že netestujete…

K čemu tedy?

Pokud se držíte metodiky TDD, tedy že nejprve píšete testy a až po nich kód, tak můžete brát psaní testů jako první použití vašeho nového kódu. Berte to jako příležitost zjistit, jak se s ním pracuje, a to ještě dřív, než ho opravdu napíšete. Uvidíte svůj kód očima jeho uživatele, což je zkušenost k nezaplacení. Třeba zjistíte, že budete muset něco v API změnit či upravit…

TDD bývá někdy některými hodnocena jako příliš ortodoxní. Asi není třeba být vždy a za všech okolností doslovný a pokud napíšete nejdřív jednoduchou knihovnu a až po ní testy, nebude to jistě žádné velké neštěstí. Jen pozor na to, že při obráceném postupu má člověk stále ještě v hlavě vlastní kód a mnohdy píše testy „na míru svému kódu a svým chybám“.

Kupříkladu píšeme funkci, u níž je parametr i, jehož hodnota smí být max. 10 (včetně). Při psaní se překoukneme a  do funkce napíšeme test, který vyhodí výjimku, když i<10. Pokud jsme nejprve napsali kód, tak máme mnohdy tendenci ověřovat, že pro i=9 projde a pro i=10 zhavaruje. Ve skutečnosti tedy testujeme to, že napsaný kód dělá to, co je v něm napsáno, nikoli že dělá to, co dělat má. Pokud začneme nejprve testem, pravděpodobně jej napíšeme správně.

Testy patří k bontonu!

Testy jsou v podobné roli jako dokumentace: programátoři mají odpor k vytváření, protože to je „neproduktivní práce“. Když člověk programuje, v hlavě mu letí myšlenky a na nějaké psaní dokumentace není čas… Maximálně tak nějaký ten komentář do kódu.

Propagátoři nových jazyků a čistého kódu hovoří o dokumentačních komentářích jako o samozřejmosti; měly by patřit do kódu stejně samozřejmě jako odsazování. Stejný pohled se začíná prosazovat i v oblasti testování. Pustit open source knihovnu do světa bez sady testů (a bez dokumentace) je v jistých kruzích už programátorské faux pas: k čemu mi je kód, který si můžu upravit, když nemůžu rychle zjistit, jestli mi úprava něco nerozbila?

Napsat dobrý test je nutnost, pokud chceme svým kódem přispět do většího projektu. I ve firmách, které nedělají open source, je často používáno automatické testování, ať už kvůli Continuous Integration, tak třeba i pro měření kvality práce programátorů – pokud někdo soustavně commituje změny, které neprojdou testem, lze to snadno dohledat a zjistit příčiny.

Testy, podobně jako dokumentace, nejsou v podstatě nikdy hotové a kompletní. To, že se v kódu objeví chyba, kterou test nezachytil, není důkaz toho, že jednotkové testování nemá smysl, ale toho, že byl test neúplný. Můžete se rozčílit na všechny propagátory testů a napsat jim to do diskusí, nebo můžete problém popsat testem; to druhé bývá rychlejší a smysluplnější. Stejně tak když vám kolega řekne, že mu vaše třída nefunguje za takových a takových podmínek: to je ideální příležitost ty podmínky nasimulovat v testu!

A nezapomeňte: dobrý test vám kryje záda, když jde do tuhého a hledá se viník!

Stejně ale…

Pro nás je to drahé a zdržuje to.

Zkusili jste si to, testy jste psali tak, jak se psát mají, všechno jste udělali správně, ale zdržovalo vás to. Knihovny totiž nikdy nepřepisujete a ty testy byste stejně spustili jen jednou. Pak asi ano, pokud jste si jisti, že jste všechno udělali správně, a přesto jste si spočítali, že se vám to nevyplatí, tak OK. 

Nám chyby v kódu nevadí.

Komu by vadily, že? Místo psaní testů vymyslíme, jak opravy kódu prodat zákazníkovi jako vícepráce, a vyděláme na tom!

Můj kód je vždy perfektní, protože jsem špičkový programátor.

Pardon, testem jsme vás nechtěli urazit. Víme, že jste špičkový stroj na kód, který není nikdy unavený, nikdy nedělá chyby, nikdy se nepřepíše, vždy je stoprocentně koncentrovaný – a že tomu věříte. Máte pro to ale i nějaký jiný důkaz než svoje tvrzení?

Všechny tyhlety takzvaný „metodiky“ jsou jen tlamocviky mladých frikulínů, které mají zakrýt, že vlastně vůbec neuměj‘ programovat…

Ale jistě… „Opravdový programátor“ napíše cyklus DO přes tisíc řádků, a nesplete se! Přidejme ještě „pravidla jsou pro slabochy“ a „čára není zeď“, ať to máme komplet. Ale upřímně – pokud si myslíte, že programování je umění, měli byste programy vystavovat na výstavách, a ne je cpát lidem do počítačů, aby s nima pracovali…

Shrnutí

  • Testy nejsou kouzlo; je to metoda. Když ji neumíte a děláte ji špatně, nebude vám fungovat, tak prosté to je.
  • Jednotkové testy testují to, co říkají: funkčnost jednotek kódu.
  • Automatizovaný test otestuje jen to, co do něj napíšete.
  • Jednotkový test nenahrazuje jiné metody testování; doplňuje je. Pokud chcete testovat, jak to bude fungovat dohromady, slouží k tomu integrační testy.
  • Jednotkové testy děláme proto, že jsou opakovatelné, automatizovatelné a jejich výstup lze strojově vyhodnotit.
  • Automatizovaný test nemá, na rozdíl od člověka, „své dny“ a vždy testuje vše tak jak má. Neznamená to ale, že můžou člověka plně nahradit – jen mu ulehčují mechanickou práci.
  • Testování není ladění.
  • Test je jen tak dobrý jako jeho autor; je-li autor lemrouch, je i test špatný.
  • Hodina vynaložená na psaní testu ušetří den hledání podivné chyby za půl roku. Pokud hodláte ještě za půl roku pracovat ve stejném oboru, zvažte tento aspekt.

Ke čtení naleznete mnoho různých materiálů, od teoretických po praktické ukázky. V češtině mě zaujala velmi podrobná Příručka o testování (pdf) od Anny Borovcové (blog).

Pokud vás problematika zajímá, využijte možnosti navštívit školení Jiřího Knesla na téma Testování v PHP (viz zkušenosti účastníků).

Komentáře

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

Já testuju nadvakrát – nejprve kód, který zrovna píšu a potom i aplikaci jako celek. Všechno ale dělám ručně, jediná „automatizovaná“ věc, kterou používám, jsou scripty, které generují náhodná data a cpou je aplikaci do chřtánu – a já sleduju jestli to někde vyplivne chybu.

Zatím jsem nenarazil na rozumný návod jak psát nějaké lepší testy. Hlavně v případě PHP mám pocit, že testování není moc v módě.

myshpa

Existuje spousta zpusobu, jak testovat. Ten uplne nejjednodussi zpusob vypada nejak takto:

function check($msg, $condition) {
echo ($condition ? „OKt“ : „FAILt“), $msg, „n“;
}

check(„value je cislo“, is_numeric($va­lue));
check(„uzivatel byl prihlasen“, $login->is_logged_in());
check(„html bylo vygenerovano“, strpos($html, ‚<body>‘)!==false);

jáchym

má někdo tip na prostředí pro unit testy v javascriptu? něco, co bude chodit na všech prohlížečích, bude se s tím hezky delat, asynchronost nebude problém?

dík

Jáchym

Ten jsem četl.

JSUnit – potřebuje tomcat
FireUnit – potřebuje firefox
QUnit – potřebuje jquery, což bych mu odpustil, ale je „… právě pro testování tohoto frameworku“, ale já potřebuju testovat cokoliv jenom je jQuery

Já ale potřebuju něco co, co je univerzální jak přes webové prohlížeče, tak přes použité knihovny a pokud možno to nemá serverovou část.

dík

Aleš Roubíček

Doporučuji JSTestDriver http://code.google.com/p/js-test-driver/

Mastodont

… Řekněme, že budeme testovat HTML generátor, který generuje stránky ze záznamů v databázi. Namísto objektu, který přebírá data z databáze, podstrčíme „mock“ – jednoduchou třídu, která má stejné rozhraní, ale na getTextById() vrátí testovací „Lorem ipsum“. …

PROČ? Píšu-li aplikaci pracující s databází, mám testovací databázi a pracuji přímo s ní. Nemám-li databázi, píšu něco jiného. Tahle část unit testingu mi přijde zcela pošahaná – pokud mi něco chybí, tak to někde splaším nebo napíšu, proč psát nadvakrát mock a pak vlastní komponentu?

tdvorak

Naprostý souhlas. Pokud spoléhám na databázi, musím zajistit že je v každém okamžiku testování konzistentní a naplněná daty která očekávám. Když použiju mock, neřeším databázi vůbec, poběží to všude (na stroji vývojáře, na serveru s continuous integration), poběží to svižně. Odhalím chybu v kódu, ne v připojení, ne ve špatné databázi. A to je to co potřebuju. Kdybych chtěl do testování zatahovat databázi, už to nebude unit test, testuji pak funkčnost celého ekosystému…

Michal Augustýn

…resp. integrační test.

jos

mastodonte sám si pošahanej

makam tady na projektu, aktuálně máme 1808 unittestů, podle tebe bych měl pro každej test inicializovat testovací databázi a ještě k tomu dost možná pokaždý jinak; ani nápad

test používající databázi není unittest!

přečti si TDD by example

Tomáš Herceg

Zajímavé je, že v článku (a nejen tam, obceně) se propagují hlavně unit testy. Nevím, jestli je to jen má zkušenost, ale většina mých testů jsou testy integrační, které testují více „jednotek“ najednou – samotné unit testy používám velmi zřídka a ještě je dost šidím (dělám do nich více assertů, což by být nemělo atd.).
V praxi se mi integrační testy osvědčily více, jelikož s kvalitními a podstatné věci pokrývajícími unit testy je nesrovnatelně více práce.
V poslední době jsem též přišel na chuť testům uživatelského rozhraní, na které se všem doporučuji podívat – ať už Selenium, nebo Code UI Tests ve Visual Studiu – ušetří to spoustu času při proklikávání u větších webových aplikacích, a i když vytvoření testů trvá třeba celé odpoledne, velmi brzy se tato investice vrátí.

Mimochodem v článku zmiňovaný příklad s CAPTCHA mi nepřijde moc šťastný – zrovna funkce, která generuje captcha nebude mít téměř žádné závislosti na okolí, takže tu bych klidně jednou po dopsání otestoval ručně a pak se s ní vůbec nezabýval – změna kódu někde jinde ji velmi pravděpodobně neohrozí.
Testovat bychom měli začít od věcí, u nichž čekáme, že se nám budoucími úpravami kódu rozbijí, a psát testy tak, aby nám pomáhaly a šetřily čas, tzn. například podívat se do source control, ve které třídě pořád něco opravujeme, a zkusit ji otestovat.

Michal Augustýn

1. Myslím si, že unit testy u mnohých tu averzi ještě prohloubí, protože člověk se rozhodne začít s testováním, ale hned narazí na problém s tím, že je třeba se nějak vypořádat se závislostí na databázi apod. A když googlí články o testování, tak najde převážně kopec příkladů, které testují třídu na sčítání dvou čísel (která tedy nemá žádné závislosti). Takový člověk pak může snadno propadnout zoufalství a na testování se vyprdnout. Nebo taky začít více hledat a ptát se zkušenějších (moje cesta).
Co tím chci říct? Unit testy jsou sice základ a na úplný začátek se hodí s nima člověka seznámit, ale co nejdříve bych takovému člověku ukázal integrační testy, který mají IMHO větší výkonnost (poměr užitek/čas).

2. Můj pohled je prakticky stejný jako Tomáše – přistupujeme k testování pragmaticky. Začal jsem psaním integračních testů, kde mám v jednom testu více assertů a píšu je dodnes.
Jak člověk do testování praxí pronikne, tak mu začne být jasné, že jdou testy psát lépe (tj. psát i unit testy), ale nemyslím si, že je to vždy nutné (vzhledem k úsilí, jaké musí člověk vynaložit na napsání supr-dupr unit testu).

Btw. když má člověk pokrytí unit testy 100 %, pokrytí integračními testy 100 %, jaké je celkové pokrytí? 200 % [joke] :-)

vlk

> ale hned narazí na problém s tím, že je třeba se nějak vypořádat se závislostí na databázi apod

Ak narazi na takyto problem, potom ma zly navrh aplikacie. To znamena, ze ten test este ani nanapisal ( pretoze ma problem ), ale uz ma vysledok ( je to zle ).

Tiez som si volakedy daaavno myslel, ze testovanie nesmie mat dopad na navrh/kod samotnej aplikacie. Opak je vsak pravdou.

Aplikaciu (moduly) je potrebne navrhovat tak, aby sa dala jednoducho unit-testovat. Vysledkom takehoto navrhu nie je iba usetrenie casu pri pisani unit-testov, ale castokrat aj cistejsi/jedno­duchsi navrh aplikacie, ktora sa lahko udrziava/modi­fikuje, ma ciste komunikacne rozhrania.

Riesenim pre mna bol dosledny prechod na pattern DependencyInjec­tion/Inversion of control

Michal Augustýn

Souhlas – chtěl jsem to napsat do toho mého prvního komentáře, ale zapomněl jsem na to :-) Tj. závislosti v aplikacích musí být dostatečně volné, aby bylo možné aplikaci rozumně otestovat.

koubel

Pokud se jede podle TDD a testy se píší před kódem, tak funguje „magie“, že netestovatelný aplikační kód prostě nenapíšete. Ono je to docela logické.

tdvorak

Selenium testy jsme začali používat relativně nedávno. Je to kus práce napsat test dobře, tak aby nebyl plný nepodmíněných čekání a nerozpadl se při prvním zásahu do ui. Na druhou stranu opravdu ušetří kupu klikání a provádí se sám, „zadarmo“, při každé nové revizi projektu. Selenium jsme si také přizpůsobili druhé formě testů, té „kouknu a vidím“. Udržujeme v chodu něco přes 20 webů a není v lidských silách po každém updatu sledovat jestli se něco nerozsypalo (layout, chybí obrázky, přetékají bločky). Proto jsme spustili selenium grid, do něj zapojili virtuální stroje, generujeme tři sady screenshotů vytipovaných důležitých stránek. Jednou pro linux/ff, jednou win/ie6 a jednou win/ie9. Tyhle obrázky se po vyrenderování natahnou do jednoduché stránky, kde není problém je za chvilku proběhnout a očima zkontrolovat, že se nic nerozpadlo. Nemusím nikam klikat, nic načítat, jen buším do mezerníku a listuju sadou obrázků. Celý proces se spouští z continuous integration serveru s commitem do stable větve gitu. Během 10 minut se vrátí email s linkem na přehled. Chce to jen zodpovědného člověka, co to na konci opravdu proběhne a podívá se že to dopadlo ok.

Tomáš Herceg

Formuloval jsem to nešťastně – testovat každou jednotku mi přijde velmi pracné a místo 150 unit testů je podle mě efektivnější (lepší poměr pracnost x užitná hodnota) napsat několik integračních testů, které testují ty samé jednotky, ale po skupinkách, a už simulují nějaké reálné scénáře. Kde je chyba, to zjistím snadno i z integračního testu, a to je cílem testování – lokalizovat chybu a umožnit její opravu.
Takže to není jako s tou pohádkou.

drevolution

Ještě jsou tu ale případy, kdy pro test nemůžeme využívat obyčejné instance tříd, ale musíme dělat mocky a unit testy psát.

Typicky v situaci, kdy se třída nechová deterministicky, je její sestavení příliš náročné, nebo je prostě používání klasických instancí výpočetně příliš drahé.

V takovém případě se hodí psát unit testy.

Ale souhlasím v tom, že integrační testy odhalí více chyb než unit testy. Unit testy pomáhají spíše návrhu.

Ped

Ja osobne kdybych delal generator CAPTCHA, tak bych si na to unit testy napsal, krome zakladnich ktere by porovnali jestli vraci obrazek pozadovane velikosti bych pak generator pustil s nejakym fixnim nastavenim a vygenerovany obrazok rucne skontroloval a pouzil jako „expected“ pro novy unit test.
Pro uplnost („triangulaci“) bych to udelal jeste jednou pro jinou sadu parametru.
Takze kdyz treba v budoucnosti vypadne z bezne instalace pozadovany font nebo se zmeni verze graficke knihovny a bude tam chyba, tak vim ze mi unit testy neprojdou a budou hlasit nesrovnalost v obrazku. Kterou jednoduse rucne skontroluji a budu alespon tusit co se deje.

Tohle uz neni uplne unit testing, to je spis QA testing, ale vzhledem k tomu ze vetsina zapeklitych chyb ktere jsem kdy ve svych aplikacich resil pochazela prave od treti strany (upgrade knihoven, platformy, chyby v kompilatorech a pod.) a ve svem kodu temer zadne nedelam, tak radeji pisu unit testy spis v „QA“ rozsahu. Setri mi to pozdeji pri udrzbe spoustu casu, kdyz presne vim kde se nejaka nesrovnalost zacina projevovat, nez ji hledat nekde o nekolik vrstev dal pote co odchylka projde nepovsimnuta skrz muj kod.

František Kučera

Ad 4) jen taková poznámka: ten můj komentář byla odpověď na otázku: „Můžete mi uvést příklad, kdy trvá řádné napsání testů dvě hodiny, A ZÁROVEŇ je možné vše, co testují tyto testy, otestovat „ručně během dvou minut“?“

Sám od sebe bych s tímhle tématem nepřišel ;-)

Michal

Ja v PHP testuju cca pul roku. Driv jsem psal stylem „pisu, pisu“, f5 – vidim.
Takovy postup Zaprve hazarduje s vysledkem v pripade, ze vyvyjim slozitejsi veci s vrstami logiky (99%) a za druhe unavuje, protoze rychlejsi psani kodu je neblaze vyvazeno hrubym odhadem 30% energie spotrebovane na soustredeni pri manualnich kontrolach funkcnosti.
Z testu pouzivam samozrejme unit (ktere vyuzivam i na blackbox testy) a potom BDD behat.

Musim doporucit tenhle trial http://www.slideshare.net/avalanche123/clean-code-5609451?from=ss_embed

rox

…od Chucka Norrisa :-)

Opravdový odborník :-)

ahoj Martine, nechci urazit, ale poslední dobou pozoruji, že se ze Zdrojáku stává něco jako tvůj blog místo IT serveru.
ne že by to občas nebylo zajímavé, ale uvítal bych trochu profesionálnější formu — psát to víc formou článků a méně zápisků do blogu.
Titulek tohoto článku taky zní jak kdyby to byl nějaký dlouhý komentář do diskuse, který nakonec vyšel samostatně.
Tak mi přijde, že se zdejší komunita trochu uzavírá do sebe a žije sama sebou — takové to „oni nám napsali nesmysli do diskuse, tak jim to vysvětlíme v článku“
a pod tím článkem je zase další diskuse… a tak pořád dokola.
Nemyslím si, že autor by měl diskusí pohrdat a vůbec tam nechodit — to by měl, a měl by snad i odpovídat, ale asi ne touto formou.

Co se týče obsahu, taky mi přijde, že to má trochu sestupnou tendenci. Jasně, chápu, že vysoce odborné články nepřitáhnou dost lidí a reklamy…
nějaký ten „povídací“ článek občas může být, ale raději si přečtu dobrý technický text než špatnou glosu – a to i kdyby ten článek byl z jiné oblasti, než kterou aktuálně řeším

Opravdový odborník :-)

Schválně jsem se dnes podíval na titulní stránku — odshora až dolů Martin Malý (až na jednu výjimku). Chtělo by to s tím něco udělat. Taky zkusím něco napsat…

valnoha

mě to přijde v cajku. článek sice reaguje na komentáře, ale je dost obecnej, takže to není nějaký dohadování uzavřený skupiny lidí, jak píšeš. nemám pocit, že je to tu blog p. malýho. jeho glosy jsou mi někdy sice proti srsti a nesouhlasím s tím co píše, ale rád si je přečtu. čistě technickejm článkům tu taky nemám moc co vytknout. to, co tu p. malý dělá, mi přijde jako rozumnej kompromis mezi čtivostí a odborností a u mě jako dobrý.

Charvi

Nemyslíš si, že by se autor měl spíš řídit svým přesvědčením, než názorem jednoho rýpala? Každopádně nechci podcenit význam kritiky :)

heptau

Zajimalo by me jestli ma nekdo nejaky napad, jak rozume testovat aplikaci psanou v databazi. Klientska cast se v podstate nemeni, ale veskera logika aplikace je napsana v databazi v ramci funkci a triggeru, prav…

Na funkce, ktere nevyzaduji data z aplikace samozrejme unit testy napsane mam, ale jakmile jsou potreba nejaka data v databazi, ktera se navic v case meni, jsem nahrany. Bylo by mozne bud data v databazi testovat s minulym casem – na serveru nastavit napr. rok 2000 a ten tam porad udrzovat, nebo neustale aktualizovat data v databazi (v mem pripade se jedna o databazi s cca 150 tabulkami, cca 600 triggery vcetne funkci a cca 400 dalsich funkci). Mam sice napsanych i nekolik dalsich testu, ktere poustim vetsinou na realnych datech (ktera se prubezne meni a akceptuji zmenu data) ovsem vysledkem je ze nad testovani stravim nekolik hodin, protoze si zduvodnuji jednotlive chyby, ktere vlastne ani chybami nejsou, ale holt v te databazi je to nastaveno jinak, nez jak jsem cekal a testoval u predchozich 20 jinych databazi.

V podstate narazim na to ze zatimco u testovani funkce nezavisle na databazi mam nekolik promennych, u funkce na databazi zavisle mam promennych nekolik set, na coz je nerealne napsat testy a pokud se nejake nekompletni testy napisou, nemaji velky vyznam.

Michal Augustýn

Pokud je to takhle zapečené všechno dohromady, tak bych to asi udělal tak (neznám přesně tvoji situaci), že bych měl vedle testovací databázi. Testovat něco jiného než read-operace na živé databázi mi nepřijde dobré (ale chápu, že okolnosti tě tam mohly dohnat).
Testoval bych pak asi nějaké use-cases a test by vypadal takto: uvedení databáze do potřebného stavu, spuštění use-casu, vyhodnocení.

Aleš Roubíček

Tak nějak si představuji programátorské peklo ;)

František Kučera

Když jsem pracoval na podobném systému, měli jsme pravidlo, že se v procedurách nesměl používat SYSDATE (nebo jeho ekvivalent v jiném SŘBD). Pokud procedura měla provést akci k určitému okamžiku, dostala přesná čas jako parametr. Nejde jen o nějaké testy, ale i o to, že je možné synchronizovat různé databáze a neohrozí to ani taková „maličkost“ že se na jednotlivých serverech rozjedou hodiny.

V triggerech je to horší, ale tam by zase šlo místo volání nativní časové funkce volat nějakou vlastní – ta se na testovacím serveru přepíše tak, aby vracela něco jiného – třeba pořád stejný čas.

Pro spouštění testů bych klidně použil JUnit framework. Nebudou to sice klasické jednotkové testy, protože se bude testovat i komunikace mezi Javou a databází, ale to ani není na škodu. Testy se dají podědit, takže toho psaní bude málo – budou téměř zcela deklarativní – jen napsat vstupní parametry a očekávaný výstup.

maio

U nas v praci jsme si udelali build skript, ktery vytvori cistou DB (nekolik schemat, x set tabulek, funkci, procedur a baliku) a pak se do ni naimportuje testovaci sada dat (dataset). Pokud to jde tak by to melo probehnout co nejrychleji aby clovek nemusel zbytecne cekat. To jsme castecne vyresili pouzitim RAM disku + optimalizaci nastaveni Oracle tak aby vytvarel objekty s minimalni velikosti.

Vzhledem k pouziti datasetu, jde lehce dohledat jake data bude nove vytvorena DB obsahovat a ty pak jdou vyuzit v testech. Po kazdem testu se v teardownu zavola ROLLBACK. Pripadne pokud se testuje neco co bezi v autonomni transakci tak si to test po sobe uklidi rucne.

maio

+1 za osvetu (unit)testovani. :) Hezky clanek.

Osobne za nejvetsi vyhody, ktere mi TDD prinasi pokladam:

1. Pokud neco prestane fungovat, tak mi Unit-Test s velkou presnosti ukaze, kde je problem.
2. Pokud je psani nektereho testu problematicke, beru to jako upozorneni na chybu v designu. (funkce/metoda/ob­jekt toho dela vic nez by mela, ma zbytecne moc zavislosti, atd…)
3. Nejdriv resim CO od nove psane metody/objektu ocekavam, a az pak to, JAK to budu implementovat.
4. Kdyz mi projdou vsechny testy – vim ze mam hotovo.

X. U web aplikaci nemusim po kazde zmene klikat jako cvicena opice dokola na to same :)

kert

A opět tady vidíme v akci skvělou fíčuru „zašedivíme jiný názor“. Usabilita naprd, informace nulová, akorát to překáží ve čtení.

Kdyby

jiny nazor. ale mne spis pripada, ze zasedivuji nahodne vybrane! jinak souhlas, je to k nicemu, ve cteni to prekazi a pouzitelne to neni.

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.