31 komentářů k článku Testování v PHP: odstiňujeme závislosti II.:

  1. Honza Marek

    vfsStream

    vfsStream bohužel není použitelný zdaleka vždycky. Například funkce realpath na virtuální soubory z vfsStreamu vždycky vrací false.

  2. Honza

    Dobrý příklad

    Líbí se mi, že příklady vkládanými mezi výklad udržujete seriál v kontaktu s realitou a tím zajímavý i pro nedočkavé čtenáře jako jsem já, kteří chtějí „už vidět jak to teda v reálu funguje“ a nechtějí čekat až na konec seriálu.

    Co jsem si z dnešního příkladu odnesl? Bohužel to vidím na potvrzení mého dosud poměrně skeptického postoje k automatizovaným testům. Co je v příkladu ukázáno:
    – testovali jsem funkci o délce 17 řádek kódu
    – udělali jsme na to dva testy, které mají dohromady přes 80 řádek kódu
    – testy testují dva případy použití (což by měla být kompletní sada možností použití metody, aby byla pokrytá testy)
    – tyto dva testy nijak nezaručily, že metoda bude skutečně fungovat správně!

    Je to výborný příklad toho, co jsem už dvakrát zmiňoval v diskuzi, a sice že testy se skutečně otestuje jen to, na co programátor myslel, že se má otestovat, tzn. co ho napadlo, že může být špatně. Pokud programátora opravdu napadne, co všechno se může stát špatně, tak to může rovnou napsat do kódu a ušetří (v tomto případě) 83% kódování. Pokud ho to nenapadne, tak ho testy nezachrání, protože tu chybu stejně neotestuje.

    A jaká je tedy i po úspěšném absolvování dvou testů v testované metodě chyba? Neřeší situaci, kdy produkt v repository existuje a má klíč „0“. Dojde k chybě – produkt se vloží nově, protože if ($productId) pro 0 neplatí. Situace s 0 by měla být nějak ošetřena, buď požít === nebo explicitně definovat v popisu interface parseru, že getCode() nesmí 0 vracet.

    1. Honza

      Re: Dobrý příklad

      Ještě aby to nevypadalo, jako že automatizované testování úplně odmítám, tak to uvedu na pravou míru: ten příklad je dobrý i proto, že jde zrovna o situaci, kdy automatizované testování zjevně smysl má – pokud budu mít několik parserů (nejlépe opravdu hodně), tak se mi rozhodně vyplatí sestavit si testy na otestování, zda funguje parser správně, navíc když je to externí kód vytvářený jiným teamem.
      Na druhou stranu na metodu, která je v příkladu, bych asi automatizovaný test nepoužil, protože není součástí parseru, ale typu, který budu zřejmě psát jen jednou. A pokud mne má test ochránit před chybami při změnách v implementaci, tak se musím opravdu zamyslet nad tím, jestli se mi vyplatí psát skoro 6x víc kódu. Jaká je pravděpodobnost, že celou implementaci 5x přepíšu? A že se přitom vůbec nezmění interface, takže budou testy dál použitelné?

      A ještě jedna poznámka: testy mohou dávat falešný pocit bezpečí – pokud to někdo udělá jako v tomto případě a začne machrovat „mám testy pokryto 100% use cases kódu“, tak se bude o to víc divit, až někdo napíše repository, které nedává produkty do databáze, ale do PHPkového pole, kde je 0 normální platný klíč.

      Čili můj názor je: automatizované testy jsou užitečné v těch případech, na které se hodí, ale mohou pouze pomoci hledat chyby – spoléhat výhradně na ně je hloupost.

      1. arron

        Re: Dobrý příklad

        Souhlasím naprosto bezvýhradně s jednou věcí. Spoléhat výhradně na unit testy je hloupost :-) Ono totiž asi žádný test nezaručí 100% jistotu, že všechno bude fungovat. My se těmi testy jenom k těm 100% přibližujeme. Odhadem bych řekl, že tímhle testem jsme zvýšili míru jistoty, že ten kód funguje správně z takových 50% (může fungovat, ale nemusí, kdo ví) na takových 95% (v drtívé většině případů funguje). A to za těch 80 řádků kódu docela stojí.

        Navíc máme hned velkýho pomocníka. Do vyjádření užitku toho unit testu se totiž musí započítat i to, že se bude provádět dokola velmi často a tím nás ujišťovat o těch 95%. Kolik by stál programátor, který by po každém commitu tenhle kousek kódu testoval ručné?? Opět mi přijde, že těch pár řádek kódu bylo řádově levnějších :-)

        Ono ve finále je tenhle test zbytečně dlouhý. Používá pouze nativní phpunit. Když se píše nějaký projekt, tak okolo těch testů stejně vznikne jakýsi „pseudojazyk“ pomocí kterého se pak budou testy psát daleko rychleji a kratšeji. Abych jenom neplácal, tak například:

        public function testUpdateProduct()
        {
        $existentProductId = 222;
        $foreignProductCode = "PROD02";
        $productName = "Test product 2";

        $product = new Product();
        $product->setName($pro­ductName);

        $this->expectDependen­cyCall(‚Produc­tRepository‘, ‚update‘, array($existen­tProductId, $product), $existentProduc­tId);
        $this->expectDependen­cyCall(‚Produc­tConversion‘, ‚exists‘, array($foreig­nProductCode), $existentProduc­tId);
        $this->expectDependen­cyCall(‚Produc­tParser‘, ‚getCode‘, NULL, $foreignProduc­tCode);
        $this->expectDependen­cyCall(‚Produc­tParser‘, ‚getName‘, NULL, $productName);

        $import = new ProductImport($re­pository, $conversion);

        $this->assertEquals($e­xistentProduc­tId, $import->import($parser));
        }

        Hle, hned je to o dost kratší :-) (přiznávám se, že používám poněkdu jinou metodu testování závislostí, ale řekněme, že je to implementační detail a pointa je jasná :-))

        1. Honza

          Re: Dobrý příklad

          Podobenství k tomu testování každého kousku kódu po každém commitu a placení programátora, který by to dělal:
          Zjistili jsme, že abychom měli doma čisté koberce, potřebujeme si je jednou ročně nechat vyčistit speciálním strojem, což stojí asi 1000 kč. Ale manželka přišla na super zlepšovák – ten stroj si koupíme. Stojí to sice 50000 Kč, ale už nebudeme muset platit za čištění firmě. Od té doby čistíme koberce pravidelně každý týden – no a co byste řekli, cena stroje se nám za rok vrátí, protože jinak bychom museli každý týden platit 1000 Kč.

          Vysvětlení, pokud to není jasné: cena vyčištění koberců = cena programátora, aby něco otestoval, cena stroje = cena programátora, aby napsal test. Čištění koberce jednou ročně = otestování kódu, zda je v pořádku při jeho vytvoření a při jakýchkoliv operacích s ním. Čištění koberce jednou týdně = automatické testy po každém commitu.
          Ale klidně můžeme ještě pokračovat: čištění jednou ročně specializovanou firmou (perfektní vyčištění od profesionála se zárukou) = kvalitní manuální otestování nad kterým se přemýšlí. Čištění týdně svépomocí jak to tak sám umím = automatizovaný test, který najde jen to, na co se myslí při jeho psaní.

          Tzn. testovat všechno po každém commitu je zbytečné. Testovat věci, kterých ten commit týká, zbytečné není.
          Každopádně ale díky za ukázku alternativního zápisu testu.

          1. EsoRimer.

            Re: Dobrý příklad

            Skvělý příklad, jen s drobnou chybkou.

            V „realitě“ to obyčejně dopadá tak, že čistějí jednou týdně vyjde na 100Kč, 1 po roce na 50000 …

            1. Honza

              Re: Dobrý příklad

              Tak teď nevím, jestli myslíte testy nebo koberce. Jestil koberce, tak fakt nevím, kdo vám je vyčistí za 100 Kč a těch 50000 je úplný nesmysl. Jestli testy, tak to trochu rozveďte co se čím myslí. Pokud má být těch 100 Kč automatizovaný test, tak ten by měl být „zadarmo“ (pokud nepočítám elektřinu na běh procesoru a drobné opotřebení počítače).

          2. arron

            Re: Dobrý příklad

            Ono v drtivé většině případů se vyplácí uklízet menší nepořádek častěji než velký bordel jednou za čas. Člověk tím pak stráví dohromady řádově víc času a zašantročí víc věcí, které pak nemůže najít. Navíc žije celou tu dobu v bordelu. Fakt to za to stojí? :-)

          3. Clary

            Re: Dobrý příklad

            A co když se jedná o koberce ve velkém hotelu, kterých je mnoho, neustále po nich někdo chodí, tahá zavazadla (souloží, zvrací, jí, močí, kálí atd.) a zákazníci hotelu při otm vyžadují aby koberce byly pořád perfektně čisté?

            1. Honza

              Re: Dobrý příklad

              Jo, to je přesně to, proč si myslím, že to docela odpovídá. Pokud vám někdo zvrací na koberce každý týden, tak rozhodně potřebujete mít vlastní stroj na čištění, což přesně většina hotelů má (předpokládám). Já ho doma nepotřebuju.

              Pokud má mít i tohle nějakou analogii k automatickým testům, tak pokud máte kód, který vám někdo mění každý týden a ještě při tom souloží, tak rozhodně potřebujete, aby to po něm někdo zkontroloval – a pokud základní kontrolu zvládne zadarmo automat, tak super.

              1. jos

                Re: Dobrý příklad

                > Já ho doma nepotřebuju.

                doma == pár commitů za měsíc

                v hotelu == komerční projekt se stovkama+ commitů za měsíc

                takže to vypadá že už se dostáváš k jádru věci a jak se k němu dostaneš, tak zjistíš že tohle srovnání s vysavačema je mimo; nakonec budeš rád, že sis napsal testy k nějakýmu domácímu projektu

                a ještě k tomu čim si tohle vlákno začal – když si tak skeptickej a pořád hledáš co přesně unittesty neřeší … nechceš se na programování radši vysrat? dyť do takovýho stadia abys vůbec nedělal chyby nebo je po sobě našel klikáním po aplikaci před každým releasem nedolezeš – to vůbec nemyslim jako urážku, to je holej fakt

                1. Honza

                  Re: Dobrý příklad

                  No, nemyslím si, že by srovnání bylo úplně dokonalé, ale když už v něm pokračuješ s velikostí projektu, tak nezáleží na tom, jak je barák velký, ale jak hodně se v něm špiní koberce. Čili pokud kód měním často, potřebuju testy, pokud jen leží, tak je psaní testů zbytečná námaha. Čili víceméně to, co říkáš ty, akorát mi přijde hloupé to vztahovat k velikosti projektu, protože že je projekt velký automaticky neznamená, že se na všech jeho částech nonstop aktivně pracuje.

                  Nehledám důvod, proč automatické testy nepoužívat, ale naopak důvod, proč je používat. Jsem skeptický, protože hledám způsob, jak si práci ulehčit (tzn. test mi pomůže) a ne způsob, jak si zbytečnou práci přidelat (tzn. budu psát test zbytečně).
                  S odpovědí, kterou mám zatím (tzn. pokud se kód měni, jsou testy potřeba a pokud ne, tak ne) jsem celkem spokojený, nicméně vnímám, že v reálu může být trochu problém dopředu odhadnout, která část kódu se bude měnit a která ne. Ale i to se dá praxí nacvičit.

                  Čili bych to viděl tak, že si počkám na další díly seriálu a uvidím :-)

                  1. arron

                    Re: Dobrý příklad

                    Další díly seriálu Ti budou IMHO k ničemu. Tohle totiž není o tom, v jakém frameworku se ty testy budou psát. Je to celé spíše filozofická otázka :-)

                    Ať už se ten projekt mění často nebo ne, před jeho odevzdáním stejně musí dojít k otestování. A unit testy (myslím si já) už v tu chvíli sehrají takovou roli, že se vyplatí :-) A i kdyby ne, a ten projekt se měnil jednou za rok, tak hned při první změně se to bohatě vrací zpět. Ono totiž při hledání chyb je ujištění o tom, že někde chyba není, poměrně klíčové :-)

                    Já vidím problém obecně v jiné věci. Myslím si, že ve firmách, které se zabývají online, se obecně netestuje. To, že někdo ten projekt tak jakože prokliká, tomu se nedá říct test. Natož, aby se dělalo regresní testování při každém uploadu čehokoliv na prokukční server. A samotný proces nahrávání už se vůbec netestuje (ačkoliv by měl). A v takovém prostředí není tolik vidět, jak široký dopad ty unit testy (a obecně automatizované testy) mají. Začít psát unit testy v takovém prostředí je, jako najmout bandu programátorů, která prochází kód pořád a pořád dokola a při každé změně provede komppletní sadu testů, takže je zajištěno i regresní testování (na úrovni unit testů samozřejmě). A to je obrovský přínos v kvalitě produktu (který nemusí byt vidět hned na první pohled).

                    Ve finále jsou unit testy jenom jední z nástrojů pro udržení kvality produktu v dlouhodobém měřítku, nicméně od nich se pak odvíjí další typy testů, šetří čas a nervy programátorů a tím umožňují firmě dlouhodobě růst a zvyšovat kvalitu svého výstupu.

                    1. Honza

                      Re: Dobrý příklad

                      Díky za komentáře, celkem asi chápu tvoje stanovisko, ale nijak zvlášť ho nesdílím. Myslím si ale, že rozhodně má smysl další díly seriálu číst, protože předpokládám, že až budu znát framework pro automatizované testování lépe, tak se budu moct lépe zamyslet nad tím, kdy testy používat a kdy ne.

                      Ještě jednu věc k tvému komentáři: „že někdo ten projekt tak jakože prokliká, tomu se nedá říct test“ – s tím souhlasím, ale stojím si za tím, že příklad testu v tomto článku ukázal, že „že někdo napíše automatický test, tomu se nedá říct testování“, protože i přesto, že automatický test prošel, tak chybu v kódu neobjevil.
                      Čili automatizované testy ano, ale nespoléhat pouze na ně a rozhodně nesdílím názor, „proklikávání stránek je k ničemu a automatické testy rovná se kvalitní kód“. Obě tyhle věci ti odhalí jiné chyby a na některé nepřijdeš ani tak ani tak.

                      1. arron

                        Re: Dobrý příklad

                        Tak dobře, ještě přecejenom odpovím ;-)

                        Když se podíváš o kousek výš (konec přízpěvku, který komentuješ), tak nemám pocit, že bych někde psal, že unit testy jsou samospasitelné a že zajistí 100% funkčnost. Ony „pouze“ zvyšují míru jistoty, že ten kód je v pořádku.

                        Na druhou stranu to, že unit testy automaticky zvyšují kvalitu kódu, za tím si dost stojím :-) Unit testy mě nutí lépe separovat kód, psát kratší a jednodužší třídy a metody (protože se daleko jednodušeji testují a já jsem líný), a nutí mě psát věci tam, kam opravdu patří (zase proto, že jinak se to o dost složitěji testuje).

                        Takže tak :-)

                  2. arron

                    Re: Dobrý příklad

                    A je tu ještě jedno zajímavé hledisko. Spoustu lidí si řekne „začnem dělat ty unit testy.“ Po měsíci, když stráví opravdu nad všim dvojnásobek času s tím seknou, že je to k ničemu. Mám obavu, že relativné málo lidí si uvědomuje, že naučit se psát a používat unit testy je běh na relativně dlouho trať. Je potřeba se naučit používat úplně nové postupy, musí se změnit způsob přemýšlení programátorů, vyvíjí se různé nástroje k tomu, aby se unit testy psaly jednodušeji a podobně. Stejně jako s jakoukoliv jinou technologií, je to proces, který trvá řadu měsíců, spíše však jeden až dva roky.

                    A není to jenom o tom „začít psát unit testy“, ale i o tom, naučit se z toho správně profitovat a pochopit širší souvislosti :-)

                    Je to prostě i trochu filozofie ;-)

                  3. jos

                    Re: Dobrý příklad

                    > ale když už v něm pokračuješ s velikostí projektu

                    nic takovýho sem napřímo netvrdil, de spíš o cvrkot v tom projektu, v hotelu (i malým) mezi recepcí a pokojem leze daleko víc lidí se zablácenejma botama než u mě doma

                    jiná analogie:
                    řekněme že bydlíme vedle sebe a ty jezdíš do stejně vzdálený práce autobusem, je to levný, nemusíš lízt do garáže a votvírat vrata, zastávku máš přímo před barákem a před prací taky, super

                    já jezdim autem, musim se procpat garáží, lejt do nádrže drahý beňo, servisovat a vůbec se zatěžovat věcma kterejma se ty zabejvat v autobuse nemusíš

                    jenže po roce, kdy sem proti tobě střádal půlhodinky denně už je kurva znát že se jízda autem vyplatí

                    1. Honza

                      Re: Dobrý příklad

                      Jo, to je taky dobrá analogie, asi ještě lepší než s tím hotelem. Protože je na tom dobře vidět, že se to nemusí vyplatit vždy a všude. Tzn. pokud bydlím ve vsi za Prahou a pracuju na okraji Prahy, tak ušetřím spoustu času a budu to mít pohodlnější. Ale pokud bydlím na Florenci a pracuju na Václaváku, tak jezdit autem může jen magor.
                      Čili pro různé situace jsou vhodné různé postupy.

  3. AntiHonza

    Vzkaz pro Honzu

    Líbí se mi, že se od té potupy, jak ses představil pod prvním článkem, snažíš navodit dojem, jak se to snažíš chápat, ale prostě ti přijde pořád zbytečné. Je chvályhodné, že se takto vyvíjíš, ale proč to neustále odsuzování testů pod článkem v komentářích? Když nechceš testovat, tak netestuj a pak si případné problémy vysvětluj podle libosti.
    Možná si jednou uvědomíš, že ty testy nejsou úplně zbytečné. Třeba až místo nějaké šablony pro WP budeš v týmu, který pracuje na rozsáhlejším projektu. Určitě není pravidlem, že by se hodily jen u velkých projektů. Mně se hodí testy pořád, když už máš více projektů a třeba se k jednomu vracíš po několika měsících, tak je snadné se pustit do úpravy kódu. Když nemám testy, tak to je jen takový výstřel, pak si sice otestuješ tu konkrétní změnu „proklikáním“, ale problém je v tom, že po delší době už občas něco zapomeneš otestovat atd. Nevím, jak přesně byl nějaký ten citát, ale s každou opravenou chybou zaneseš do kódu chyby další. Dodal bych, že bez testů jich zaneseš 5 až nekonečno, s testy 1 až 10. Čísla ber hodně s nadsázkou.
    Možná už to padlo, pro unit testy existuje pěkná zkratka FIRST (http://pragprog.com/magazines/2012-01/unit-tests-are-first). S tvým stylem bych se zamyslel nad F a R. Nehodlám už na tebe nijak reagovat ani odpovídat, testuje ten, kdo chce. Když nechceš, tak je to tvoje věc, tak ale potom je přeci zbytečné komentovat každý článek, který tě v podstatě nezajímá a ani ti nic nepřináší.

    1. Clary

      Re: Vzkaz pro Honzu

      Třeba si narozdíl od nás ostatních uvědomuje, že celé je to jen lobby testovacího průmyslu, který si koupil i takové lidi jako Robert C. Martin a Martin Fowler, aby o testování psali ve svých knihách :)

    2. Honza

      Re: Vzkaz pro Honzu

      Díky za vzkaz, ačkoliv mi připadá poměrně agresivně laděný, takže se omlouvám, pokud jsem tě zbytečně naštval. Komentáře k prvnímu článku si budu muset asi znovu přečíst, potupu jsem nějak nevnímal.

      Vcelku se nestydím za to, že neznám framework pro automatizované unit testy pro PHP a nepoužívám ho, ale nebráním se tomu se o něm něco dozvědět a třeba tento svůj postoj změnit, a proto čtu seriál. V komentářích se člověk dozví spoustu zajímavých doplňkových informací a názorů, takže celkem vidím přínos i v nich.
      Ačkoliv ti přijde, že ve svých příspěvcích automatizované testy odsuzuju, tak se spíš snažím hledat nějaké argumenty nejen „pro“, ale i „proti“, hlavně proto, abych si ujasnil, kdy má a kdy nemá smysl automatizované testy používat.

      A skutečnost, že automatický test neodhalí chybu, která v kódu v článku je, mi připadá jako poměrně zajímavá i pro jiné čtenáře, protože poukazuje na to, že automatizované testy nejsou samospásné a nemohou být jediným způsobem pro zajištění kvality výstupu. (Což možná někomu připadá samozřejmé, ale asi by to mělo být u takovéhleho seriálu explicitně řečeno.)

      Jinak doufám, že ti to nebude vadit, ale budu číst seriál dál, protože mám pocit, že mi něco přináší, a případně to budu i komentovat.

  4. Jakub Vrána

    Kvalita testu

    Představme si, že budeme chtít kód trochu zjednodušit. Třeba tím, že si výsledek $parser->getCode() uložíme do pomocné proměnné. Kód bude možná maličko přehlednější, nepatrně rychlejší, ale jinak bude všechno fungovat naprosto stejně. Tedy všechno, až na takto napsaný test.

    Nebo si představme, že kód budeme chtít optimalizovat. Třeba zavoláním INSERT ... ON DUPLICATE KEY UPDATE místo SELECT; INSERT; UPDATE. Bude to zhruba dvakrát rychlejší, ale jinak to fungovat naprosto stejně. Tedy až na test.

    Nebo si představme, že si seznam všech objektů načteme předem a uložíme je všechny do paměti, abychom je nemuseli načítat jednotlivě. Opět to bude zhruba dvakrát rychlejší, ale jinak to bude fungovat stejně. Až na test.

    Takto napsaný test od testování odrazuje – jakákoliv změna v kódu znamená i změnu v testu. Údržba takovéhoto testu je skutečně jen zbytečná práce navíc a mnoho hodnoty nepřináší.

    1. Josef ZamrzlaAutor příspěvku

      Re: Kvalita testu

      Jakube, těší mě, že Vás můj seriál zaujal, nicméně musím zopakovat, že uvedené příklady jsou vždy ilustrativní a jejich účelem je především navození „AHA efektu“, ne ukázka high performance řešení. Ostatně i celý seriál je koncipován pro čtenáře, kteří mají s testováním v PHP žádné nebo minimální zkušenosti.

      Ad 1) Výsleden $parser->getCode() není ukládán do proměnné záměrně kvůli ukázce chyby v předpokladu (v test case je volána dvakrát, ne jednou).

      Ad 2) V zadání nepadlo ani slovo, že repozitář pracuje zrovna s relační databází, už vůbec ne že danou databází je právě MySQL :-)

      Každopádně, děkuji za Váš postřeh, pokud bude po každém dílu obsahující nějaký příklad následovat několik pull-requestů s nápady jak příklad vylepšit, budu jen rád. Přesně proto je vše dostupné na Githubu. Bohužel, zatím se nic takového nestalo.

      1. Jakub Vrána

        Re: Kvalita testu

        „Aha“ efekt z tohoto příkladu by pro mě jako začátečníka byl ten, že psát testy vyžaduje neustálé synchronizování kódu a testu. Špatné příklady jsou nejhorší právě pro začátečníky, protože zkušenější pochopí, co tím chtěl asi autor říct.

        Vhodný příklad by mohl testovat pomalou metodu, jejíž výsledky si kešuji. U takové metody bych chtěl ověřit, že se zavolá jen jednou, dokud nezměním cache key, kdy se zavolá znovu.

        O implementaci skutečně nejde. Kód by mohl volat insertOrUpdate, což by někde fungovalo jako současné řešení a někde rychleji. Test by se opět rozbil.

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=3735