Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: nm 03. 05. 2012, 18:00:55
-
Nedávno jsem si přečetl něco o metodice "Vývoj programu řízený testy" v knize o JAVA programování. Jedná se o metodu, při níž nejprve vytvoříte vhodné testy, kterými program testujete a teprve potom se pustíte do samotného programování. Testy pak průběžně program ladíte.
Používáte tuto metodu? Používáte jí v práci nebo i doma?
-
Nepoužívám. Upřímně, přijde mi to ujeté. Samozřejmě se nedomnívám, že by někdo dělal testy na to, zda 1 + 1 == 2, jak se píše v učebnicích, ale myšlenka, že by testy měly "řídit" vývoj aplikací, podle mě poukazuje víc na deficit používaného programovacího jazyka, který nedovoluje dobře modelovat problém. Kdybych chtěl být jízlivý, přejmenoval bych TDD na MPO (metoda pokus-omyl).
-
Na neco to pouzivame, na neco ne. S deficitem jazyka to podle mne nijak nesouvisi a s metodou pokus-omyl uz vubec ne. Pokud je zamerem mit dobre pokryti testy, tak se napsat musi stejne a kdyz jsou k dispozici predem, muze to samotnemu vyvoji hodne pomoct. Protoze pokud se pisou testy dodatecne, tak se obcas nenapisou vubec a kazdiopadne vznika casovy usek, kdy testy jeste nejsou. A dobre pokryti testy je hlavne pri vyvoji ve vetsim tymu docela vyhra, potoze spolecna codebase splnuje nejake zakladni pozadavky na kvalitu (nedostane se tam kod, ktery vzdy spadne apod.) - je opravdu fatalni, kdyz deset lidi ztrati dve hodiny proto, ze nekdo "opravil" funkci ve spolecne knihovne tak, ze pro jeho potreby funguje a ostatnim zacne padat.
-
TDD je celkem narocna metodika. Programtor opravdu musi vedet, co dana aplikace/jeji cast musi umet a dale musi programtor znat technologii, ci rozhranii frameworku.
Psani TDD je specifikace, jak ma program fungovat. Pri pouzivani TDD se napise malo kodu, za to kvalitniho, protoze cilem je, napsat co nejmin kodu, ktery vyhovi testu zatim co test rika, co pozdeji napsany kod ma vlastne delat.
Doporucuji TDD pouzivat
-
Tak já myslím, že TDD je například nutnost když se programuje v dynamickém jazyce - ten jazyk za programátora prostě spoustu věcí nezkontroluje a refaktoring je poměrně velké riziko - obzvlášť čím větší je tým a projekt. V tom případě pokud není program pokryt mnoha testy, je větší refaktoring šílenství.
V Javě se někde dělá, jinde ne - z mojí zkušenosti jsou úspěšné týmy i ty, které TDD dělají i ty, které TDD nedělají.
Podotýkám, že je důležité, aby testy byly opravdu jednotkové - namockovat co nejvíc použitých služeb/komponent, co to jde. Důležité je, aby test procházel i pokud ja pokažená / změněná komponenta, na které testovaný kód závisí. Jinak totiž s narůstajícím počtem testů je vůbec problém udělat úpravu kódu, aniž by člověk musel opravit stovky testů - to by totiž paradoxně s narůstajícím počtem testů vývoj zpomalovalo nebo téměř zastavilo a v té chvíli by se všichni na testy vykašlali a testy by měly nulovou vypovídací hodnotu.
-
I v dynamických jazycích je možná statická analýza (my např. v Pythonu používáme Pylint); tam ta kontrola je s Javou docela srovnatelná. Úplně se na ni ovšem spolehnout nedá.
Neříkám, že jednotkové testy jsou na nic, ale obávám se, že ve větších systémech se na ně stejně nedá plně spolehnout; jsou situace, které jednotkovými testy nedají moc dobře postihnout. Čím víc se člověk snaží postihnout všechno, tím více se vývoj protahuje a pak je samozřejmě na zvážení, který náklad se ještě vyplatí.
Mimochodem, kód, který projde testy, ještě nemusí být kvalitní.
-
Mimochodem, kód, který projde testy, ještě nemusí být kvalitní.
Nekvalitní kód, který projde testy, znamená jediné: Nekvalitní testy. Nevěř testům, které projdou.
-
Z pohledu projekt manažera - teoretika bych najmul geniálního matematika, aby analyticky dokazoval správnost algoritmů. V praxi se musí řešit náklady na implementaci metodiky vývoje sw, dodací lhůty, nebo fluktuace zaměstnanců(správa know-how). Při ladění se často uvádí pravidlo 80/20, nicméně u firmy, která již disponuje řadou sw polototovarů, které se podle zadání integrují, mohou jednotkové testy urychlit dodací lhůty.
-
Jasně, testy mohou být neúplné nebo chybné, ale o to mi nešlo. Chtěl jsem říci, že jsou i jiná kritéria, např. optimalita a udržovatelnost.
Mimochodem, kód, který projde testy, ještě nemusí být kvalitní.
Nekvalitní kód, který projde testy, znamená jediné: Nekvalitní testy. Nevěř testům, které projdou.
-
Nekvalitní kód, který projde testy, znamená jediné: Nekvalitní testy. Nevěř testům, které projdou.
Jasně, testy mohou být neúplné nebo chybné, ale o to mi nešlo. Chtěl jsem říci, že jsou i jiná kritéria, např. optimalita a udržovatelnost.
Testy se dělají i kvůli těmto kritériím. Kvůli udržovatelnosti se dělá refaktoring, který se s testy dělá mnohem lépe.
Testy dělá každý. Ovšem ne každý je dělá systematicky. Když napíši sort, připravím si zkušební data a výsledek porovnám s požadavkem. Nikdo nepustí program do světa bez testu. Mezitím někdo modifikuje knihovnu nebo proběhne upgrade serveru - může se změnit prostředí. Pokud ten test mezitím nikdo nesmazal, je velmi jednoduché ho spustit znovu a ověřit si tak, že aplikace šlape stále jak má.
Testy mi také ukáží, zda mé pokusy o optimalizaci nenaruší požadavky na aplikaci. Ano, testy se dají využít jako specifikace požadavků s možností opakovaného ověřování. Když budu vývoj řídit testy, stále to ještě neznamená psaní neudržovatelného kódu.
Test považuji za další level kompilátoru či interpretru, který má za úkol odhalit logické chyby v aplikaci.
-
TDD jsem nikdy nepouzival, a osobne si myslim, ze lepsi je pri programovani vyuzivat abstrakci a ruznych assertu nez testovat (protoze to jsou fakticky testy nad nekonecnou mnozinou pripadu). (A take mi prijde legracni tvrzeni nekoho tady, ze chce psat malo kodu - pokud nepisete v jazyce, ktery umi metaprogramovani, zapomente na to, ze budete psat "malo" kodu! :-))
Nicmene, ted me napada, neporusuje TDD princip "krizove validace" ve statistice? Tedy zasadu, ze pokud neco vyvijime (nejaky model reality, programy jsou specialni pripad) na nejakych datech, meli bychom ho testovat na jinych datech? Zvlaste ta predstava, ze ty testy se musi stejne napsat, tak proc to nepsat tak, aby to rovnou temi testy proslo - to je desive! Lidi, uvazujte trochu..
A jak rikam. Pokud uz povazujete za dobre mit test primo pri vyvoji, proc tam nevrazit rovnou assert, ktery je obecnejsi?
-
A jak rikam. Pokud uz povazujete za dobre mit test primo pri vyvoji, proc tam nevrazit rovnou assert, ktery je obecnejsi?
Sice nejsem nějaký skalní příznivec TDD, ale tady se musím testů zastat. Test může např. kontrolovat, že metoda vyhodí správnou výjimku, nebo že zavolá jinou metodu na nějakém jiném objektu. Nebo třeba že vrátí výsledek do určitého času. To jsou věci, které assertem nepokryješ.
A druhá věc je, že umožňují oddělit logiku aplikace od testů, takže kód není zahnojený všemožnými kontrolami (které by byly při běžném provozu stejně vypnuté a aplikovali by se jen ve fázi vývoje a testování).
-
A jak rikam. Pokud uz povazujete za dobre mit test primo pri vyvoji, proc tam nevrazit rovnou assert, ktery je obecnejsi?
Pokud někdo dává assert do aplikace, vkládá do ní testy. TDD tyto testy odděluje do samostatného kódu, který může většinu času jen nečinně ležet vedle aplikace a spouštět se jen v případě nějaké změny. Nezvětšuje tedy kód aplikace a zbytečně ji tím nezpomaluje.
-
Jasne ze pouzivam, kdyz nemam po ruce nejakou *unit knihovnu a moznost testy poustet, pripadam si jak bez jedne ruky. Ted treba zrovna pisu knihovnu pro zpracovani dat nejakych mericich pristroju, kterou budou pouzivat jini, a vidim to asi nasledovne:
Stejne bych musel nejak vyzkouset, ze ta knihovna neblbne, zrejme si napsat nejaky programek ktery bude generovat/cist od uzivatele data a koukat se, jestli to dava vysledky jake ocekavam. Doufat, ze kdyz se to prelozi, tak to i spravne funguje, je furiantstvi a blbost. Proc teda rovnou nenapsat testy, ktere vygeneruji nejaka vzorova data a kouknou jestli vysledky odpovidaji ocekavani? Prace je to nakonec stejne...
Kdyz knihovnu navrhuji, snazim se o to, aby se co nejsnaze pouzivala. Kdyz si nejprve napisu testy, ktere tu knihovnu pouzivaji, dobre si uvedomim, jak verejne rozhrani navrhnout. Pak uz jen dodam implementaci knihovny :-)
Az budou chtit ostatni clenove tymu knihovnu pouzivat, musi mit nejakou dokumentaci, jak se s ni zachazi. Tests to the rescue :-) Vzdyt jsou to vlastne male priklady, jak knihovnu pouzit. Staci mi napsat nejaky textovy dokument popisujici high-level prehled knihovny a jeji rozdeleni, konkretni pouziti pak uz mohou obslehnout z testu. Navic, takovato dokumentace je vzdy up-to-date, coz se o textove da malokdy rici...
Jak rika Donald Knuth, "premature optimalization is the root of all evil", takze to pisu tak, aby to fungovalo a bylo to citelny. Az mi sef rekne "Hele funguje to dobre, ale chtelo by to 100000x zrychlit a at to zere 100000 min pameti", muzu hledat slozitejsi algoritmy a optimalizovat, a vzdy mi pak staci jen pustit testy a ujistit se ze jsem nic nerozbil.
Takze treba v tomhle pripade jasna vyhra. Jsou veci co se testuji hur (GUI, komunikace s externim prostredim, weby), ale pokud to jde, ma smysl testy psat.
-
Zvlaste ta predstava, ze ty testy se musi stejne napsat, tak proc to nepsat tak, aby to rovnou temi testy proslo - to je desive! Lidi, uvazujte trochu..
A jak rikam. Pokud uz povazujete za dobre mit test primo pri vyvoji, proc tam nevrazit rovnou assert, ktery je obecnejsi?
Asi nechapes, o jake testy se jedna. Nikdo neprogramuje tak, aby vyhovel testum, ty mu pouze pomahaji kontrolovat, ze neudelal chybu. A chyby dela kazdy. Automatizovane testy typicky kontroluji vztah vstup-vystup, pripadne aspekty chovani jako treba zavolani jine metody apod., pokud jsou definovany jako pozadavek v zadani. Ja kdyz naprogarmuju funkci, tak si ji po sobe otestuju - pokud to udelam opakovatelnym zpusobem (napr. JUnit), tak to bude moci udelat i kdokoliv dalsi, kdo tu funkci bude upravovat, a nebude ho to stat zadne usili. O to jde v automatizovanem testovani.
Kdyz vidim nektere softwarove produkty, kde se ob verzi periodicky vraceji drive opravene elementarni chyby typu "pro vice nez 8 parametru konci chybou" (u mne v tomto vedou JDBC drivery od Oracle), tak si rikam, proc nepouzivaji testy? To je presne vec, ktera se pri dobrem pokryti testy nemuze stat. Coz nesouvisi s TDD, testy nejakym zpusobem provadi kazdy, jde spis o otazku jejich efektivity.
-
Testy maju jedno nadherne pouzitie odhaluju chyby ktore sa uz raz nasli.
Teda ked tam ma SW chybu napisem test ktory ju odhali. Pred releasom pustim testy.
Pretoze nieje nic horsieho ako ked dodate zakaznikovi SW stale s tymi istymi chybami.
-
A jak rikam. Pokud uz povazujete za dobre mit test primo pri vyvoji, proc tam nevrazit rovnou assert, ktery je obecnejsi?
Pokud někdo dává assert do aplikace, vkládá do ní testy.
Test neni totez co assert. Assert testuje predpoklad, ktery ma byt splnen vzdy. Test testuje nejakou malou konecnou mnozinu pripadu (vetsinou jen jeden). Na druhou stranu, ne vse co lze proverit testem lze proverit assertem - napr. test na spravnost vysledku funkce faktorial lze tezko assertovat (aniz bychom napsali tentyz kod 2x).
Ja si myslim, ze pokud muzete zvolit mezi assertem a testem, assert je ucinnejsi. Napr. staticka typova kontrola je jedna z forem assertu. Nejucinnejsim nastrojem je ovsem vhodna volba abstrakce. Ta chybam predchazi rovnou v dusledku dekompozice problemu.
Co se tyce toho, zda se ten assert da odstranit nebo ne, zalezi na jazyku a frameworku. Uzitecne jsou oba typy assertu.
-
Asi nechapes, o jake testy se jedna. Nikdo neprogramuje tak, aby vyhovel testum, ty mu pouze pomahaji kontrolovat, ze neudelal chybu.
Proti tomu nic nenamitam. Ale jak mam tedy rozumet tomu "testy se stejne musi napsat"? Pokud si nekdo mysli, ze TDD muze nahradit normalni testovani, je podle me na omylu. I ja jsem zastance toho, aby si vyvojar sve veci otestoval, ale to neznamena, ze tim lze nahradit nezavisle testy.
-
Ale jak mam tedy rozumet tomu "testy se stejne musi napsat"? Pokud si nekdo mysli, ze TDD muze nahradit normalni testovani, je podle me na omylu. I ja jsem zastance toho, aby si vyvojar sve veci otestoval, ale to neznamena, ze tim lze nahradit nezavisle testy.
[/quote]
Pokud chci mit pokryto automatizovanymi testy, musi se tyto testy napsat, to je asi jasne. TDD je metodika, ve ktere se zjednodusene receno nejprve pripravi testy a pak se implementuje. Testy se ale klidne daji psat az dodatecne, pokud to nekomu lepe vyhovuje. O nahrade testovani jako takoveho nebylo vubec reci - cilem automatizovaneho testovani je zajistit, ze budou splneny elementarni invarianty, napriklad spravne osetrene mezni stavy apod., coz zvysuje "zakladni" kvalitu kodu a usnadnuje refaktoring a optimalizace. Testovani testery je velice drahe - zatimco cena automatickeho testu pravidla "pro prazdny vstup vraci nulu" je rekneme minuta na napsani testu, objeveni NPE na tomtez miste v ramci "nezavisleho testovani" muze stat v souctu hodiny prace nekolika lidi. To neznamena, ze prislusny scenar v uzivatelksych testech nebude, jen to zvysuje sanci, ze probehne uspesne.
-
Pokud chci mit pokryto automatizovanymi testy, musi se tyto testy napsat, to je asi jasne. TDD je metodika, ve ktere se zjednodusene receno nejprve pripravi testy a pak se implementuje.
Jadro naseho sporu je v tom, jak se TDD stavi k tomuto: http://en.wikipedia.org/wiki/Testing_hypotheses_suggested_by_the_data (http://en.wikipedia.org/wiki/Testing_hypotheses_suggested_by_the_data) (Statistiku moc neznam, jen vim, ze ten problem existuje a je treba dat si na nej bacha.) Tedy, jinak receno, jsou ty testy dostupne neomezene behem vyvoje, nebo se pouziji az po jeho skonceni? Pokud to prvni, hrozi riziko, ze napisete program ne tak, aby byl spravny, ale aby prosel testy.
Mimochodem, extremni pripady a vadne vstupy jsou prave ty situace, kde je IMHO vhodnejsi assert. Nerikam, ze by se to nemelo testovat, jen ze mi prijde napsat tam assert jako ucinnejsi metoda nez napsat na to test. Samozrejme zalezi na tom, jak to podporuji nastroje - me pripada podpora assertu v modernich jazycich dost nedostatecna, spis se resi prave to TDD, coz mi prijde tak trochu krok stranou (o tom, ze treba Java nepodporuje metaprogramovani vubec - a vhodna abstrakce je nejucinnejsi forma predchazeni chybam - nemluve; a jeste to dost lidi povazuje za vyhodu).
-
Nevim sice co je assertion, jeste jsem to nepochopil. Ale asi zalezi na tom, jak kvalitne se ty testy napisou. To ale taky jeste neni uplne ono. Protoze v tom odkazu na Wikipedii je jasne patrny, ze i nejlepe napsane testy muzou v jistych pripadech selhat.
Podle mne je to podobny tomu, jako kdyz lidi delaji pristani modulu s posadku na Mesic v laboratornich podminkach. To jsou taky takove testy (at uz primo simulace pristani nebo matematicke dokazani spravnosti vypoctu), ale neznamena to, ze jsou 100%-ni. Nejlepsim testem je fakt s tim modulem na tom Mesici pristat a mit s sebou vsechny merici pristroje, ktery kontrolujou spravnost toho pristani a vyhodnocujou chyby. Ale ani tenkrat to jeste neznamena 100%ni vyhru. Tech pristani by se musela udelat cela rada. A porad se jeste vyskytne chyba v dalsim pristani. To bysme museli znat 100%-ne vesmirnou fyziku a buhvi co jeste.
Tudiz testy samozreme teda ano. Plati pro ne asi podobny pravidlo, jako pro programovani. Pokud si myslis ze je software bez chyb, vzdycky tam nejaka chyba jeste je.
Otazka ale zrejme zni, co je lepsi - jestli assert nebo test. Vypada to, ze kazdy z nich je dobry na neco. Takze asi by bylo dobry rict, na co je perfektni assert a na co je naopak vynikajici test, ci TDD?
-
Nevim sice co je assertion, jeste jsem to nepochopil. Ale asi zalezi na tom, jak kvalitne se ty testy napisou. To ale taky jeste neni uplne ono. Protoze v tom odkazu na Wikipedii je jasne patrny, ze i nejlepe napsane testy muzou v jistych pripadech selhat.
Assert je kontrola, ze je v danem miste/okamziku behu programu splnena nejaka podminka (viz C makro assert). Muzou byt pouzite jak pri ladeni, tak v realnem nasazeni (zalezi na tom, jak moc chcete mit program odolny vuci chybam navrhu vs. efektivitu zpracovani/psani).
Vyhoda assertu je, ze testuji neomezenou mnozinu pripadu. Priklad - dejme tomu funkce f(a,b) dvou parametru, kde a nesmi byt 0. Test zkousi konkretni dvojici hodnot a,b a porovnava vysledek. Assert testuje primo, zda a je nerovno 0. Takze assert selze pro libovolnou hodnotu b.
Na druhou stranu, nevyhoda assertu je, ze tezko muzete pomoci assertu overit vysledek funkce samotne, aniz byste zduplikovali jeji funkcionalitu. A take ty nastroje - uz to tu nekdo zminoval, ale to je spis prakticky problem.
U testovani je to vzdycky o tom, jak moc automaticke chcete testy mit. Uplne automaticke testy s totalnim pokrytim znamenaji fakticky napsat aplikaci znovu jeste jednou a porovnavat vysledek s tou puvodni. Pokud se spokojite s necim mensim (jako ze v praxi temer vzdycky :-)), pak vam staci otestovat omezenou mnozinu pripadu.
-
Vyhoda assertu je, ze testuji neomezenou mnozinu pripadu. Priklad - dejme tomu funkce f(a,b) dvou parametru, kde a nesmi byt 0. Test zkousi konkretni dvojici hodnot a,b a porovnava vysledek. Assert testuje primo, zda a je nerovno 0. Takze assert selze pro libovolnou hodnotu b.
Tady se právě dost liší zaměření jednotkových testů a assertů uvnitř kódu. Zatímco test bude kontrolovat hlavně to, že funkce bude pracovat správně na svém definičním oboru, assert kontroluje hlavně to, že odjinud nevolám tuto funkci se špatným vstupem – což naopak jednotkové testy nekontrolují a selžou až v případě, že selže ta volaná funkce.
-
Zatímco test bude kontrolovat hlavně to, že funkce bude pracovat správně na svém definičním oboru, assert kontroluje hlavně to, že odjinud nevolám tuto funkci se špatným vstupem – což naopak jednotkové testy nekontrolují a selžou až v případě, že selže ta volaná funkce.
Nemusi byt pravda. Assert muze take kontrolovat obor hodnot funkce, invarianty datovych struktur, zda nedoslo k preteceni atd., nejenom predavane parametry.
-
Může být. Ale pak je trochu otázka, jestli ta funkce není moc dlouhá/komplexní – když jde někam doprostřed vložit assert, který zkontroluje mezivýsledek, možná by to mohly být dvě funkce, kde jedna vytváří vstup pro druhou (neříkám, že vždy).
BTW: když píšeš o assertech, tak to myslíš tak, že se použijí ve fázi testování (program se bude pouštět na testovacích datech), nebo že budou zapnuté i normálně v ostrém provozu?
-
Podle me zakladni rozdil mezi asserty a unit testy je v tom, ze asserty odhali pripadne chyby az pri behu programu, zatimco unit testy to umoznuji v podstate kdykoliv se rozhodnu zjistit si, zda prochazeji - kdyz neco "opravim", zmenim, vymenim behove prostredi, knihovny, atp... Unit testy pustim pri vyvoji klidne 20x za hodinu. S asserty musim pustit samotny testovany program, a pokud mozno jej pri behu donutit projit vetve, ktere asserty obsahuji, to proste zdrzuje a neni to spolehlive. Tim nerikam ze asserty nemaji sve pouziti, prinejmensim mohou usnadnit hledani chyb a take castecne dokumentuji definicni obor prijimanych parametru a obor navratovych hodnot funkci, ale ty ctyri veci co jsem zminoval ve svem predchozim prispevku
- pomoc pri navrhu kodu, lepsi rozmysleni architektury a zpusobu pouziti
- nahrada rucniho testovani, opakovatelnost testu, + jak tu nekdo zminoval, zajisteni ze jiz jednou opravene chyby se nebudou vracet
- vetsi duvera ve vlastni kod, obzvlaste pri refaktoringu, optimalizacich, upgrade pouzitych knihoven
- vzdy up-to-date dokumentace s priklady k pouzivani testovaneho kodu
proste nemohou asserty nahradit. Vyznam kazdeho je jinde.
-
Pokud chci mit pokryto automatizovanymi testy, musi se tyto testy napsat, to je asi jasne. TDD je metodika, ve ktere se zjednodusene receno nejprve pripravi testy a pak se implementuje.
Jadro naseho sporu je v tom, jak se TDD stavi k tomuto: http://en.wikipedia.org/wiki/Testing_hypotheses_suggested_by_the_data (http://en.wikipedia.org/wiki/Testing_hypotheses_suggested_by_the_data) (Statistiku moc neznam, jen vim, ze ten problem existuje a je treba dat si na nej bacha.) Tedy, jinak receno, jsou ty testy dostupne neomezene behem vyvoje, nebo se pouziji az po jeho skonceni? Pokud to prvni, hrozi riziko, ze napisete program ne tak, aby byl spravny, ale aby prosel testy.
To není riziko, to je v jistém smyslu záměr. Tyto testy (v TDD) totiž neslouží primárně jako otestování implementace, ale jako definice s dokumentace sémantiky (ovšem udržovaná tak aby odpovídala reálnému stavu, což u "papírové" dokumentace nelze).
Pokusím se to demonstrovat na jednoduchém ilustračním příkladu: píšeme funkci která vypočítá artimetický průměr seznamu čísel. API je asi celkem jasné. Do testu napíšu několik jednoduchých případů (jeden prvek, několik prvků), v podstatě jen jako náhradu read-eval-print, to není zas tak důležité. Důležitý je speciální případ: co když jako parametr předám prázdný seznam? Záleží na návrhu API, buď to může být akceptovaný parametr a výsledkem bude NaN (nebo Inf?), v takovém případě se do testu doplní patřičný check (a assert tady nemá smysl). Jiné pojetí je takové, že prázdný seznam není platná vstupní hodnota a pokud o zavolání skončí s výjimkou / assertem. Pak do testu doplním check, který mi otestuje že tam ten assert je a má správnou podmínku. Pokud v testu není ani jedna ze těchto možností, tak je to špatné - po roce už nikdo nebude vědět, zda je prázdný seznam opravdu správný parametr nebo zda je chybějící assert bugem.
O čem že měl být ten spor?
-
O čem že měl být ten spor?
Spor byl o prednostech assertu oproti testum.
JS - je zastance vyuzivani abstrakce pri programovani + assertu a tvrdi, ze testy jsou platne pro konecnou mnozinu dat (oproti assertum, ktere plati pro nekonecnou mnozinu dat). Tim padem TDD, podle nej, porusuje zasadu "krizove validace" ve statistice...
Tedy zasadu, ze pokud neco vyvijime (nejaky model reality, programy jsou specialni pripad) na nejakych datech, meli bychom ho testovat na jinych datech? Zvlaste ta predstava, ze ty testy se musi stejne napsat, tak proc to nepsat tak, aby to rovnou temi testy proslo ...
Franta - neni skalni priznivec TDD, ale zastava se testu, ktery dokaze pokryt to, na co je podle nej assert, nevyhodny...
Test může např. kontrolovat, že metoda vyhodí správnou výjimku, nebo že zavolá jinou metodu na nějakém jiném objektu. Nebo třeba že vrátí výsledek do určitého času. To jsou věci, které assertem nepokryješ.
A druhá věc je, že umožňují oddělit logiku aplikace od testů, takže kód není zahnojený všemožnými kontrolami (které by byly při běžném provozu stejně vypnuté a aplikovali by se jen ve fázi vývoje a testování).
Zda se tedy, ze assert je vyhodny tam, kde jsou slabe stranky testu a test je vyhodny tam, kde by pouziti assertu cinilo vetsi problem nez pouziti testu. Oba dva tedy maji sve vyhody a nevyhody. Takze me zajimalo, jake jsou vyhody assertu (kde je ho lepsi pouzit) a jake jsou vyhody testu.
Osobne bych se ale vratil k samotnemu TDD (Vyvoji rizenem testy) a jeho pouziti. Protoze se zda, ze testy jsou potreba, bud jako TDD nebo samostatne testy. Dovolil bych si diskusi tedy rozsirit i o dalsi metody testovani softwaru (napr. assert). Takze moje otazka zni:
Jaka je praxe v pouzivani testovacich metod pri programovani v praci (praxi)? A jake testovani pouzivate pri domacim programovani?
-
To není riziko, to je v jistém smyslu záměr. Tyto testy (v TDD) totiž neslouží primárně jako otestování implementace, ale jako definice s dokumentace sémantiky (ovšem udržovaná tak aby odpovídala reálnému stavu, což u "papírové" dokumentace nelze).
Pokud je to skutecne tak, pak mi TDD prijde tedy pekne padle na hlavu. Dokumentace, ktera v realu testuje semantiku je prave ten assert. Vy neverite programatorovi, ze tam napise assert, ale verite, ze si na ten specialni pripad napise test. Ja budu radsi, kdyz tam da ten assert, at je jasne, jak to ma byt, a nemusime hadat z testu (to dalsi, testovat assert mi prijde uz uplne ujete, ale to spis z praktickych duvodu). Hezky je ten rozdil prave videt na pripadu funkce 2 parametru, kde jeden nesmi byt nula - tam zadnou konecnou mnozinu dvojic parametru nemuzete prokazat, ze jeden z parametru ma byt nenulovy na konecne mnozine.
Svym zpusobem mam pro to pochopeni. Lepsi nastroje existuji na TDD a asserty moc ne (nebo jeho bratricka design by contract). Ale vydavat to za vyhodu? Proc mi to jen pripomina tento clanek: http://devgrind.com/2007/04/25/how-to-not-solve-a-sudoku/ (http://devgrind.com/2007/04/25/how-to-not-solve-a-sudoku/)
-
Dokumentace, ktera v realu testuje semantiku je prave ten assert.
Ale nemůže otestovat všechno.
Už to tady zaznělo: jak pomocí assertu otestuju, že funkce při nulovém argumentu vyhodí konkrétní výjimku s konkrétními daty?
-
To není riziko, to je v jistém smyslu záměr. Tyto testy (v TDD) totiž neslouží primárně jako otestování implementace, ale jako definice s dokumentace sémantiky (ovšem udržovaná tak aby odpovídala reálnému stavu, což u "papírové" dokumentace nelze).
Pokud je to skutecne tak, pak mi TDD prijde tedy pekne padle na hlavu. Dokumentace, ktera v realu testuje semantiku je prave ten assert. Vy neverite programatorovi, ze tam napise assert, ale verite, ze si na ten specialni pripad napise test. Ja budu radsi, kdyz tam da ten assert, at je jasne, jak to ma byt, a nemusime hadat z testu (to dalsi, testovat assert mi prijde uz uplne ujete, ale to spis z praktickych duvodu). Hezky je ten rozdil prave videt na pripadu funkce 2 parametru, kde jeden nesmi byt nula - tam zadnou konecnou mnozinu dvojic parametru nemuzete prokazat, ze jeden z parametru ma byt nenulovy na konecne mnozine.
Svym zpusobem mam pro to pochopeni. Lepsi nastroje existuji na TDD a asserty moc ne (nebo jeho bratricka design by contract). Ale vydavat to za vyhodu? Proc mi to jen pripomina tento clanek: http://devgrind.com/2007/04/25/how-to-not-solve-a-sudoku/ (http://devgrind.com/2007/04/25/how-to-not-solve-a-sudoku/)
Me tedy prijde, ze z tebe mluvi totalni nepochopeni toho, co to vlastne Unit testy jsou.
Unit test ti overuje ***PRI VYVOJI***, zda je tvoje implementace funkce pro pocitani prumeru kolekce cisel korektni (pro [1, 2, 3] vraci 2) a zaroven specifikuje, jak se vlastne ma chovat v mene zjevnych pripadech (ma pro prazdny seznam vyhodit vyjimku? Vratit NaN?)
Assert overuje, zda se pri vykonavani funkce ***PRI BEHU PROGRAMU*** nevyskytl nejaky nepovoleny stav, nejcasteji zda funkce nebyla zavolana s neplatnymi parametry (napr. pokud podle specifikace nema byt mozne funkci pro pocitani prumeru predat prazdnou kolekci, hodis tam precondition assert, unit testem si pak muzes overit, ze funkce podle ocekavani pri zavolani s prazdnym seznamem skutecne vrhne assertovou vyjimku). Pokud ovsem specifikace napriklad prikazuje vratit pro prazdny seznam NaN, zadny assert ti zde nepomuze - pradny seznam je podle takoveto specifikace platna hodnota, pro kterou se vrati definovany vysledek. Ze se tak funkce skutecne chova ti jiz pri vyvoji umoznuje overit unit test.
Vetu s funkci dvou parametru, kde jeden ma byt nenulovy, jsem nepochopil. Nerozumim tomu, jak lze "prokazat ze neco ma byt nejake". Hezci priklad mi prijde prave ten s funkci pro pocitani prumeru, ktera bere jeden parametr, kolekci cisel.
Co ti na Unit testech ted prijde padle na hlavu? Mj. odkazuji na sve predchozi prispevky, kde jsem zminil i dalsi vyhody unit testu. Netvrdim ze jsou vselek a mely by se pouzivat uplne vsude, ale po trosce praxe (jako vse v programovani je treba si je nejprve osahat na nejakem vhodnem projektiku) je podle me clovek nemuze alespon v nekterych pripadech neocenit.
-
Už to tady zaznělo: jak pomocí assertu otestuju, že funkce při nulovém argumentu vyhodí konkrétní výjimku s konkrétními daty?
Ano, tohle narazi na limity assertu v mnoha jazycich (napriklad v Common Lispu by makro na takovy assert nebyl problem vytvorit). Proto rikam, ze nemaji takovou podporu v jazycich jako testy, a to je skoda! Protoze jsou obecnejsi.. Ale principialne v tom problem neni - neni problem mit assert, ktery otestuje soucasne vstup a vystup z funkce (vyjimka je jen specialni druh navratove hodnoty).
Druha vec je, ze existuji ruzne druhy chyb. Ja bych treba testovani toho, zda vyjimka vyhodi konkretni (nejspis ladici) data pri chybe povazoval za zbytecne. To uz mi pripada jako testovani kompilatoru. Nakonec se na neco spolehnout musite, a pokud ne, eventualne skoncite tak, ze napisete v podstate vsechno 2x (taky moznost, nic proti, ale je to tradeoff).
-
Dokumentace, ktera v realu testuje semantiku je prave ten assert. Vy neverite programatorovi, ze tam napise assert, ale verite, ze si na ten specialni pripad napise test. Ja budu radsi, kdyz tam da ten assert, at je jasne, jak to ma byt
Tak znova: co když tam ten assert být nemá? Jistě, pokud bych měl nástroj ("nonassert"), tak by to šlo... ale výsledek pak bude stejný.
Hezky je ten rozdil prave videt na pripadu funkce 2 parametru, kde jeden nesmi byt nula - tam zadnou konecnou mnozinu dvojic parametru nemuzete prokazat, ze jeden z parametru ma byt nenulovy na konecne mnozine.
Tato věta sice není zcela pochopitelná, ale to je jedno. Já nechci prokazovat, že parametr není nenulový - já chci prokazovat, že je taková situace ošetřena definovaným způsobem.
Svym zpusobem mam pro to pochopeni. Lepsi nastroje existuji na TDD a asserty moc ne (nebo jeho bratricka design by contract). Ale vydavat to za vyhodu?
Jistě, TDD je rezignace na implementaci "design by contract" pomocí silného typování. To je důvod proč vzniklo a je klíčové v jyzacích jako je smalltalk, ruby, python.
Proc mi to jen pripomina tento clanek: http://devgrind.com/2007/04/25/how-to-not-solve-a-sudoku/ (http://devgrind.com/2007/04/25/how-to-not-solve-a-sudoku/)
Protože je tam zmíněna základní odpověď: they are mainly about achieving software quality, not correctness
Celé hledání jakéhosi rozporu mezi asserty a unit testy je prostě nesmyslné.
-
Me tedy prijde, ze z tebe mluvi totalni nepochopeni toho, co to vlastne Unit testy jsou.
Nemam nic proti unit testum, proti cemu namitam je:
- Jejich pouzivani tam, kde jsou asserty jasne lepsi (jako treba u tech null situaci). A nebo v situacich, kde by bylo lepe zvolit dalsi abstrakci. Napriklad na overeni toho, zda funkce vraci spravne debug data. Idealni by bylo mit abstrakci, ktera toto zajistuje napric celou aplikaci; tim se zaruci, ze se vykonava stejny kod ve vsech situacich. Proste jsem pro predchazeni chybam nez jejich hledani pomoci testu.
- Jejich pouzivani namisto specifikace (viz niz).
- Vyvijeni funkci tak, aby prosly unit testy, a nikoli tak, ze se napise funkce a testy zvlast a pak se to otestuje. Proste pri vyvoji by se melo dbat na to, abychom nenapsali funkci, ktera sice projde testy, ale je vnitrne logicky zcela nesmyslna. Toho se obavam u filozofie TDD, i kdyz je mi jasne, ze to kazdy chape trochu jinak.
Asserty se nemusi nutne testovat pri behu - to je Cckove omezene chapani - svym zpusobem je formou assertu i staticka typova kontrola.
Vetu s funkci dvou parametru, kde jeden ma byt nenulovy, jsem nepochopil. Nerozumim tomu, jak lze "prokazat ze neco ma byt nejake". Hezci priklad mi prijde prave ten s funkci pro pocitani prumeru, ktera bere jeden parametr, kolekci cisel.
Protoze ten muj argument na funkci s jednim parametrem nefunguje. :-) Dejme tomu mam funkci na deleni dvou cisel div(a,b). Muzu otestovat co se stane div(1,1), div(2,0), div(50,3), div(0,7), div(0,0). Ale fakt, ze div(2,0) a div(0,0) ma podle testu selhat, nevypovida o tom, ze div(a,0) ma selhat pro libovolne a. Tohle testuje assert, protoze to je podminka na nekonecnou (nebo alespon neprakticky velkou) mnozinu pripadu. Takze jako specifikace jsou testy nedostatecne.
-
Už to tady zaznělo: jak pomocí assertu otestuju, že funkce při nulovém argumentu vyhodí konkrétní výjimku s konkrétními daty?
Ano, tohle narazi na limity assertu v mnoha jazycich (napriklad v Common Lispu by makro na takovy assert nebyl problem vytvorit). Proto rikam, ze nemaji takovou podporu v jazycich jako testy, a to je skoda! Protoze jsou obecnejsi.. Ale principialne v tom problem neni - neni problem mit assert, ktery otestuje soucasne vstup a vystup z funkce (vyjimka je jen specialni druh navratove hodnoty).
Tak, a máme unit test, i když přímo v kódu, protože máme lepší nástroje a nemusíme je oddělovat. Pěkné. Klasiká metadiskuse "všechno je blbost, protože v Lispu to lze udělat také a nazvat to jinak"
-
Tak znova: co když tam ten assert být nemá? Jistě, pokud bych měl nástroj ("nonassert"), tak by to šlo... ale výsledek pak bude stejný.
Co kdyz bude specifikace spatne? Budete delat specifikaci specifikace, protoze se nekdo pri psani specifikace mohl splest? Nekde to musite utnout, a konstatovat, ze tohle je to, co chcete. Ze to narazi na limit programovacich jazyku rikam od zacatku.
Tato věta sice není zcela pochopitelná, ale to je jedno. Já nechci prokazovat, že parametr není nenulový - já chci prokazovat, že je taková situace ošetřena definovaným způsobem.
A co takhle mit abstrakci, ktera to osetruje, a o ktere vime, ze uz funguje? Nebylo by to snazsi? Zase, od urcite chvile prestavate testovat program a zacinate testovat kompilator.
Protože je tam zmíněna základní odpověď: they are mainly about achieving software quality, not correctness
No, a ja si proste myslim, ze nejdriv bychom se meli pokusit o tu korektnost (tedy pouzivat asserty a abstrakce) a pak az teprve o tu "kvalitu" (ve skutecnosti to prvni v mnohem postihuje to druhe). TDD dava prednost tomu druhemu na ukor spravnosti, a i kdyz mam jiste uvahy v tomto smeru, nepovazuji tento pristup obecne za spravny.
-
Tak, a máme unit test, i když přímo v kódu, protože máme lepší nástroje a nemusíme je oddělovat. Pěkné. Klasiká metadiskuse "všechno je blbost, protože v Lispu to lze udělat také a nazvat to jinak"
Ne, to je nepochopeni. S tim oddelovanim je to syntakticka zalezitost (a take vec vkusu - me treba prijde prakticke oboji). Lisp davam jako priklad, protoze je to jazyk, ktery takovou vec umoznuje postavit bez zmen v syntaxi (i kdyz co je v pripade Lispu vlastne syntax je otazka :-)). Jak to ovsem oddelit/schovat je zalezitost nastroju, ktere pro asserty zatim moc neexistuji, pro testy ano.
-
Co kdyz bude specifikace spatne? Budete delat specifikaci specifikace, protoze se nekdo pri psani specifikace mohl splest? Nekde to musite utnout, a konstatovat, ze tohle je to, co chcete. Ze to narazi na limit programovacich jazyku rikam od zacatku.
Tak znova a znova: toto je právě to utnutí. Zda je specifikace špatně nebo neřešíme. Důležité je, že víme jaká je, že víme co autor chtěl. Jistě, není to moc a mohou být efektivnější způsoby...
A co takhle mit abstrakci, ktera to osetruje, a o ktere vime, ze uz funguje? Nebylo by to snazsi? Zase, od urcite chvile prestavate testovat program a zacinate testovat kompilator.
Jistě že by to bylo snazší. A ano, je nutné stanovit nějakou hranici. A ano, možnosti jsou omezené, podle toho jaké mám nástroje. V určitém okamžiku (který leckdy nastane i okamžitě) se už nevyplatí. Není potřeba snažit se o absolutní dokonalost, je to jen řemeslnický nástroj.
Protože je tam zmíněna základní odpověď: they are mainly about achieving software quality, not correctness
No, a ja si proste myslim, ze nejdriv bychom se meli pokusit o tu korektnost (tedy pouzivat asserty a abstrakce) a pak az teprve o tu "kvalitu" (ve skutecnosti to prvni v mnohem postihuje to druhe). TDD dava prednost tomu druhemu na ukor spravnosti, a i kdyz mam jiste uvahy v tomto smeru, nepovazuji tento pristup obecne za spravny.
S tou první větou se dá asi jen souhlasit, zase netuším kdo má jako zastávat opačný názor.
Druhá věta: citation needed! Já tvrdím že TDD je jen doplněk, který se s používám assertů a abstrakcí (a mnoha dalšími věcmi) kombinuje (částečně překrývá). Přínosy jsou, samozřejmě, omezené a hodně závisí na dostupných nástrojích. Popularita pak může záviset na různých věcech: v některých jazycích se uchytil hlavně kvůli chybějící typové kontrole, jinde získal popularitu kvůli chybějící read-eval-print loop, v "agilním hnutí" pak kvůli ulehčení problému se synchronizací dokumentace/specifikace (aneb "programování ve wordu").
Problém samozřejmě je, pokud se někdo na něco upne a nevidí okolí. These is no silver bullet...
-
Druhá věta: citation needed! Já tvrdím že TDD je jen doplněk, který se s používám assertů a abstrakcí (a mnoha dalšími věcmi) kombinuje (částečně překrývá).
Pokud vnimas TDD takto, tak zadna citace neni potreba. To spolu v podstate souhlasime (i kdyz ja bych testy volil az na poslednim miste). Ale to neni to, co tu tvrdili jini lide - takze zalezi, co se pod TDD chape. Nekdo tu psal, ze TDD dovoluje, aby testy slouzily jako specifikace. To mi prijde spatne.
Take mi prijde spatny pristup, kdy napisu kod, ktery mi neni 100% jasny (tedy nemam v hlave formalizovanou jeho spravnost), napriklad, nevim, proc se dela nejaky prikaz, ale protoze projde testy, prohlasim ho za spravny. Pokud je toto TDD (nebo ho tak nekdo vnima), mam s tim problem. Protoze to je presne to, na co narazim odkazem na statistiku.
Jinak unit testy jsou tu uz desitky let, to neni zadna novinka. Takze co noveho prinasi TDD? Zda se, ze na to kazdy ma jiny nazor.
-
Už to tady zaznělo: jak pomocí assertu otestuju, že funkce při nulovém argumentu vyhodí konkrétní výjimku s konkrétními daty?
Ano, tohle narazi na limity assertu v mnoha jazycich (napriklad v Common Lispu by makro na takovy assert nebyl problem vytvorit). Proto rikam, ze nemaji takovou podporu v jazycich jako testy, a to je skoda! Protoze jsou obecnejsi.. Ale principialne v tom problem neni - neni problem mit assert, ktery otestuje soucasne vstup a vystup z funkce (vyjimka je jen specialni druh navratove hodnoty).
Tohle je podle me principialni problem, se kterym ti Common Lisp nepomuze. Assert nekontroluje chovani, ale stav. Stejne tak nesouhlasim s tvym tvrzenim, ze staticka typova kontrola je forma assertu. Staticka typova kontrola probiha pri prekladu, asserty se kontroluji za behu. To je take zasadni rozdil (proto jsem to v predchozim prispevku psal kapitalkami a jeste uzavrel do hvezdicek) oproti unit testum, ktere se neprojevuji pri samotnem behu programu, ale poustis je zvlast. Myslim ze moje chapani assertu je konzistentni s http://en.wikipedia.org/wiki/Assert , pokud ty osobne vnimas asserty nejak jinak, nasli jsme asi jadro nedorozumeni.
-
Myslim ze moje chapani assertu je konzistentni s http://en.wikipedia.org/wiki/Assert , pokud ty osobne vnimas asserty nejak jinak, nasli jsme asi jadro nedorozumeni.
Nevim, me prijde, ze ten clanek oznacuje za asserty i takove, ktere se overuji jen pri prekladu. Kazdopadne, i kdybychom pripustili jen tu runtime definici assertu, tak jaky je rozdil mezi testem a assertem? V obou pripadech musi testovany kod bezet, aby bylo mozne ho overit; a u nekterych assertu je mozne je nechat je z kodu pozdeji automaticky vypustit.
-
Ano, tohle narazi na limity assertu v mnoha jazycich (napriklad v Common Lispu by makro na takovy assert nebyl problem vytvorit). Proto rikam, ze nemaji takovou podporu v jazycich jako testy, a to je skoda!
V těch obecných řečech nějak ztrácím představu, jak by to mělo v praxi vypadat. Snad ne promatkupřírodu takhle?! :)
def funkce(a):
if a==0:
t = NejakaVypecenaVyjimka()
assert(a==0 and isinstance(t,NejakaVypecenaVyjimka))
throw(t)
Protoze jsou obecnejsi..
Jak se to veme... Pokud mám asserty, které v release buildu vypnu, tak jsem pomocí nic reálně otestoval stejně jenom nějakou podmnožinu vstupů a výstupů - konkrétně takové, které vznikly při testování před releasem. V provozu potom stejně můžou vzniknout situace, který jsem neotestoval.
Pokud by měl být assert opravdu obecný, musel by být na vyšší úrovní - testovat, že taková hodnota tam z principu být nemůže a ne jenom to, že v tomto konkrétním běhu programu tam aktuálně není.
-
JS: Super, myslim ze i kdyz se budeme bavit jen o runtime definici assertu, dojdeme k uzitecnym zaverum. Bez ztraty obecnosti budu hovorit o testovani jedine funkce, muzeme si predstavit napriklad tu co pocita prumer prvku ciselne kolekce.
Je samozrejme pravda, ze v obou pripadech musim testovany kod spustit. Lisi se ovsem
- jak jej spoustim
- co vlastne overuji
Unit testy:
- spousteni: Kazdy jeden unittest je mozne vnimat jako miniprogramek, ktery skutecne spusti testovanou funkci s nejakymi vzorovymi daty, a overi, ze funkce vrati ocekavany vysledek. Diky integraci IDE a ruznych *unit knihoven, ktere usnadnuji psani unit testu, se pri psani testu vetsinou mohu soustredit primo na volani funkce a overovani bez nejakeho balastu jako je definice main funkce apod., at uz testuji ve smalltalku nebo v C. IDE mi vetsinou nabizi tlacitko, ktere spusti bud vsechny testy pro projekt, nebo testy ktere souvisi s kodem ktery prave upravuji, nebo napr. testy, ktere naposledy neprosly. Ve smalltalku je tak spusteni, provedeni a zobrazeni vysledku treba i nekolika set dobre napsanych testu otazka nekolika vterin.
- co overuji: Ze funkce se ocekavane chova pro vzorova data (tj. pro platne hodnoty vraci korektni vysledky, pro neplatne hodnoty napr. hodi AssertionError, DivisionByZero, podle specifikace), tedy v podstate spravnost implementace. Samozrejme nemohu pokryt celou mnozinu vstupnich hodnot, ale uz tak je to neco, co mi pouhe asserty vubec neumozni, a pri vhodnem vyberu testovacich dat (ten zavisi hlavne na intuici programatora - je potreba si uvedomit, ze testy pisu pro svoje vlastni dobro, a proto se je pokousim napsat tak, aby pokryly prave ty moznosti kde treba tusim nejakou zradu nebo problemy v implementaci), vyrazne zvednou duveru v to, ze testovany kod je spravne.
Asserty:
- spousteni: To, ze vlozim nejaky runtime assert do tela nejake funkce, nijak nesouvisi s tim, jak bude tato funkce volana. Pokud jde o knihovni funkci, je treba zrejme napsat nejaky testovaci program, ktery funkci pouziva (pokud pobezi automatizovane bez uzivatelskeho vstupu, jedna se v podstate o unit test), pripadne, pokud knihovnu pouziji rovnou v nejakem programu, tak v nem klikam, dokud jako programator znaly vnitrnosti nezpusobim domnele vyvolani testovane funkce, a kdyz to nespadne, doufam ze je to v poradku. Treba se tam ovsem nedoklikam ja ale az zakaznik, nebo se tam doklikam, o mesic pozdeji funkci "chytre" zoptimalizuji protoze profiler mi ukazal ze je to bottleneck, a budu zase dumat jak si overit ze jsem neudelal botu.
- co overuji: Ze stav parametru, dosazitelnych promennych, navratove hodnoty atp. je pri konkretnim volani platny. Vicemene neoveruji, zda se funkce chova podle specifikace.
-
JS: Super, myslim ze i kdyz se budeme bavit jen o runtime definici assertu, dojdeme k uzitecnym zaverum. Bez ztraty obecnosti budu hovorit o testovani jedine funkce, muzeme si predstavit napriklad tu co pocita prumer prvku ciselne kolekce.
To je vsechno sice hezke, ale kde je tvoje pointa a jak to souvisi s TDD? Vsechno, co jsi rekl, jsem uz naznacoval vys v diskusi. Nejsem proti unit testum, jsem proti urcitemu zpusobu jejich pouzivani. A jasne jsem napsal, ze pokud toto je TDD, je to proste spatna metodologie.
-
To je vsechno sice hezke, ale kde je tvoje pointa a jak to souvisi s TDD? Vsechno, co jsi rekl, jsem uz naznacoval vys v diskusi. Nejsem proti unit testum, jsem proti urcitemu zpusobu jejich pouzivani. A jasne jsem napsal, ze pokud toto je TDD, je to proste spatna metodologie.
Mym cilem nebyla pointa, jen diskuze s nekterymi tvymi nazory, s kterymi jsem nesouhlasil, a i kdyz tvrdis, ze vse co jsem rekl, jsi naznacoval jiz drive, nektere tve vyroky jsem puvodne vnimal jinak (:
TDD jsem nikdy nepouzival, a osobne si myslim, ze lepsi je pri programovani vyuzivat abstrakci a ruznych assertu nez testovat (protoze to jsou fakticky testy nad nekonecnou mnozinou pripadu) Stale si myslis ze asserty dokazou nahradit unit testy?
Ja si myslim, ze pokud muzete zvolit mezi assertem a testem, assert je ucinnejsi. Podle me jsi srovnaval nesrovnatelne
Tedy, jinak receno, jsou ty testy dostupne neomezene behem vyvoje, nebo se pouziji az po jeho skonceni? Pokud to prvni, hrozi riziko, ze napisete program ne tak, aby byl spravny, ale aby prosel testy. Testy jsou dostupne behem vyvoje, pokud jsou spravne napsane, takove riziko je dost male. Programator, ktery by se tak choval, by byl sam proti sobe.
Mimochodem, extremni pripady a vadne vstupy jsou prave ty situace, kde je IMHO vhodnejsi assert. Nerikam, ze by se to nemelo testovat, jen ze mi prijde napsat tam assert jako ucinnejsi metoda nez napsat na to test. Opet, kazde slouzi k necemu jinemu. Psat testy na extremni pripady mi prijde v poradku.
Ano, tohle narazi na limity assertu v mnoha jazycich (napriklad v Common Lispu by makro na takovy assert nebyl problem vytvorit). Proto rikam, ze nemaji takovou podporu v jazycich jako testy, a to je skoda! Protoze jsou obecnejsi.. Ale principialne v tom problem neni - neni problem mit assert, ktery otestuje soucasne vstup a vystup z funkce (vyjimka je jen specialni druh navratove hodnoty). Takovy assert je problem, pokud netestuje stav, ale vztah vstupu a vystupu, pak se jedna o defacto duplikaci implementace funkce.
Nemam nic proti unit testum, proti cemu namitam je:
- Jejich pouzivani tam, kde jsou asserty jasne lepsi (jako treba u tech null situaci). A nebo v situacich, kde by bylo lepe zvolit dalsi abstrakci. opet, asserty zde nejsou lepsi, plni jinou ulohu, nedaji se s testy srovnat. Mmchd, pokud pises test, zda funkce assertuje neplatna data, nemusis testovat i presny format debugovacich vypisu, v praxi ti staci, ze jde o AssertionError, a na to uz unit test smysl napsat ma.
No, a ja si proste myslim, ze nejdriv bychom se meli pokusit o tu korektnost (tedy pouzivat asserty a abstrakce) a pak az teprve o tu "kvalitu" (ve skutecnosti to prvni v mnohem postihuje to druhe). TDD dava prednost tomu druhemu na ukor spravnosti, a i kdyz mam jiste uvahy v tomto smeru, nepovazuji tento pristup obecne za spravny. Asserty ti nijak nezajistuji korektnost, pokud tedy nepovazujes za korektni chovani to, ze kdyz se ti program dostane do nepovoleneho stavu, tak spadne. Ano, asi je to korektnejsi nez kdyby generoval nesmysly, ale ja si pod korektnim programem predstavim takovy, ktery se do nepovoleneho stavu nedostane.
Nekdo tu psal, ze TDD dovoluje, aby testy slouzily jako specifikace. To mi prijde spatne. Ne nutne, je videt ze nemas s unit testy zkusenost. Vyvoj programu pokryteho testy typicky vypada tak, ze hledam nejakou funkci, ktera by se mi mohla hodit, kdyz ji najdu, samozrejme me zajima jak presne se chova a jak ji pouzit. Najdu si jeji testy, a podle prikladu pouziti vetsinou velice dobre zjistim, jak reaguje na ocekavane a neocekavane vstupy. Nikdy se nestane, jako se to v praxi u textove dokumentaci casto stava, a velice obtizne tomu jde zabranit, ze by test neodpovidal realite. Jako specifikace tak mohou slouzit v praxi velice dobre, byt treba ta funkce nema rigorozne popsanou semantiku - zase si muzu byt jisty, ze ten popis neni obsolete, coz je castokrat horsi nez kdyby nebyl zadny.
A jak souvisi Unit testy s Test Driven Development? Mozna te zklamu, ale na to se mi nechce odpovidat :-) Jen jsem chvilku tahal pilku za unit testy (nj, rootovska captcha)
-
Zásadním rozdílem je to, že assert není testem, nýbrž jen formou kontroly - pouze ověřuje, že data, jež někam předávám nebo odněkud získávám splňují nějaké podmínky. Že kde je očekáváno číslo opravdu bude číslo, že kde je očekáván chybový kód bude opravdu chybový kód a ne nějaké nespecifikované hausnumero.
Unit test není kontrolou, ale testem. Tj. krmí náš program (modul, funkci...) sadou testovacích dat a odškrtává si, zda na ně přišla očekávaná reakce.
Příklad:
Program na výpočet dne v týdnu na základě data můžu vybavit assertem, jenž ověří, že měsíc je 1:12 a den je 1:28, resp. 29, resp. 30, resp. 31 v závislosti na měsíci a přestupnosti daného roku. Ale test bude tomu programu předhazovat sérii různých kombinací dnů, měsíců a roků a bude testovat, zda přišla očekávaná odezva - tj. správný (předem vypočtený) den v roce, resp. správný typ chyby v případě úmyslně nesprávných dat. To assert nedovede. Assert jen kontroluje. Assert netestuje. Kontrola je defenzivní, zatímco test je ofenzivní.
Report assertu: chyba - zadán nesprávný počet dní v měsicí (29 v únoru nepřestupného roku).
Report unit testu: a.b.abcd - úterý (OK), e.f.efgh - sobota (OK), g.h.ghij - chybný počet dní, ghij nebyl přestupný (OK), i.j.1570 - středa (FAILED! správně má být úterý)
A je nám hned jasné, že programátor zapomněl na kalendářní reformu. Nevím, jak tuhle chybu odhalí assert.
-
To je vsechno sice hezke, ale kde je tvoje pointa a jak to souvisi s TDD? Vsechno, co jsi rekl, jsem uz naznacoval vys v diskusi. Nejsem proti unit testum, jsem proti urcitemu zpusobu jejich pouzivani. A jasne jsem napsal, ze pokud toto je TDD, je to proste spatna metodologie.
Může být… Ale jak se rozhodneš, že program už je dokonalý nebo aspoň dost dobrý na to, abys ho pustil do světa? Budeš hodnotit spíš ten vnitřek programu (koukat programátorovi přes rameno a ptát se ho, jestli rozumí každému řádku a stojí si za ním) nebo spíš chování programu, které ověříš nějakým testem (klidně manuálním, nemusí být automatický a už vůbec ne jednotkový)?
-
Zásadním rozdílem je to, že assert není testem, nýbrž jen formou kontroly - pouze ověřuje, že data, jež někam předávám nebo odněkud získávám splňují nějaké podmínky. Že kde je očekáváno číslo opravdu bude číslo, že kde je očekáván chybový kód bude opravdu chybový kód a ne nějaké nespecifikované hausnumero.
Proto je lepší nepoužívat obecné typy (int, string atd.), ale nějaké vlastní, kde si ohlídáš, že můžou nabývat jen těch správných hodnot (např. že věk osoby nemůže být záporný a nemůže být větší než třeba 200 let nebo že e-mailová adresa není obyčejný String, ale musí splňovat určité podmínky). A pak není potřeba ani ten assert.
-
Před časem jsem začal přemýšlet nad tím, k čemu jsou jazyky s dynamickým typováním - konkrétně python a jeho ducktyping. Nemyslím tím vlastní jazyk, ale právě tu netypovost. Vždyť staticky typované jazyky jsou mnohem pohodlnější. Počínaje nápovědou IDE a konče tím, že si navrhnu applikací pomocí tříd a pak ho tak nějak seskládám do hromady.
Samozřejmě trošku zjednodušuji, ale ten pocit jsem měl.
Díky příspěvkům v tomto vlákně jsem to zdá se pochopil. Zkusím to rozebrat, třeba mi k tomu řeknete něco zajímavého.
Vezměme si třeba takovou Javu jako zástupce staticky typovaného jazyka (Ada by prý byla lepší, ale nemám zkušenosti). V Javě si logiku programu rozdělím do jednotlivých tříd, nejlépe podle návrhových vzorů. Tyto třídy si otestuji, zda dělají co mají, vytvořím instance těchto tříd a pak se mi aplikace skoro sama poskládá z těchto instancí. Přeložím a mám hotovo. Samozřejmě to není jen tak. Díky tomu, že vytvářím konkrétní typy tříd, tak mi půlku pracovní doby trvá, než vychytám všechny ty typové nesoulady.
V případě Pythonu, jako zástupce dynamického typování, to bude podobné, s tím rozdílem, že zde nemám tu kostru typové kontroly. Tudíž na jednu stranu nic mi nebrání jako parametr nějaké metody dát zcela cokoliv, a díky tomu se pěkně zamotat v chybách zanořených v naprosto nečekaných místech, na druhou stranu nemusím se s překladačem dohadovat kdo má pravdu. O různých kouzlech ani nemluvě.
Uvažoval jsem dál, k čemu je tedy dobrá ta silná typová kontrola. Tak například když budu psát unittesty pro Javu, tak nemusím kontrolovat, zda mi do objektu vlezl správný objekt. To mi ošetří překladač. (V Pythonu musím ověřit nejen, že mi tam vlezl správný objekt, ale také, zda je validní.) To znamená, že když bych byl schopen vytvořit typ, který určí, že hodnotou instance můžou být pouze řetězce reprezentující validní email, nemusím v žádném unittestu kontrolovat, zda příchozí instance emalu obsahuje validní hodnotu. (Samozřejmě unittest pro ten vlastní typ napsat musím.) Takže když postoupím o krok dál v úvaze, když bych byl schopen vytořit pro každý typ pravidlo, které normálně píšu do integračních, nebo dokonce do unittestů, nemusel bych pak tyto testy psát. Každé přeložení zdrojáků by bylo zároveň korektní prověření testů. O Adě se říká, že jakmile ji jednou přeložíte, tak funguje bez chyby. U Javy to tedy evidentně nestačí, a nějaké ty testy psát musíme. Ale kdyby...
A tak si možná návrháři pythonu řekli, že když je tak těžký dotáhnout tu typovou kontrolu do stavu, kdy by stačil jen překlad, tak co na to jít z druhé strany? Vykašlat se na typy úplně, nechat je jen jako informaci pro reflexi, a říct vývojáři, že odměnou za to, že bude psát více testů je to, že ho kompilátor nebude tolik otravovat.
Ono psát v pythonu bez testů prostě nejde.
-
kompilator tu neni od toho aby te buzeroval, ale aby te upozornoval na chyby. Beru ho spis jako radce a ne kretena kterej mi rika co a kde mam spatne
-
O Adě se říká, že jakmile ji jednou přeložíte, tak funguje bez chyby. U Javy to tedy evidentně nestačí, a nějaké ty testy psát musíme. Ale kdyby...
Ada je od toho hodně daleko, spíš se tomu blíží Haskell (a troufám si říci že je to jeho nosná myšlenka).
Jinak celkově se se o pomůcky pro lidi, ne pro stroje. Na výsledné programy to teoreticky nemá žádný vliv.
-
O Adě se říká, že jakmile ji jednou přeložíte, tak funguje bez chyby. U Javy to tedy evidentně nestačí, a nějaké ty testy psát musíme. Ale kdyby...
Ada je od toho hodně daleko, spíš se tomu blíží Haskell (a troufám si říci že je to jeho nosná myšlenka).
Je jasné, že dobrý typový systém (a Haskell má zřejmě jeden z nejlepších) pomáhá hodně a věci, které umí např. Template Haskell (typová kontrola formátovacích parametrů pro *printf při kompilaci a podobné možnosti), se jinde moc nevidí. Na druhou stranu, projekty typu Darcs ukazují, že Haskell sám o sobě všechny chyby nevychytá.