12 komentáře “Mock testing – Potěmkinovy vesnice

  1. Zpětný odkaz: Testování Java aplikací at blog glog blopt

  2. No – nevím jestli jsem pochopil dotaz správně. Tento článek rozebírá automatické testování aplikace, které se provádí v průběhu vývoje aplikace. S vlastním produkčním během nemá nic společného.

    Jde nám o to, abychom si při vývoji ověřili, jak se bude chovat naše aplikace (v tomto příkladě konkrétně business objekt) chovat v konkrétních situacích. Otestovat si chování business objektu tak, že si lokálně aplikaci spustíme a vytáhneme drát ze zdi není ideální způsob testování ze dvou důvodů:

    – existují situace, kdy danou situaci z její podstaty nemůžeme reálně na vývojovém prostředí vůbec navodit
    – takový test musíme provádět ručně – nám jde ale o to aby ani při dalších změnách v aplikaci nemohlo dojít k zanesení nějaké chyby, která by měnila chování naší aplikace v dané situaci

    Proto používáme automatické testy, které pouštíme jak lokálně při vývoji aplikace, tak ideálně i na nějakém integračním serveru, který je společný pro celý tým. S vlastním produkčním během aplikace nemají testy „vůbec nic společného“, krom toho, že výrazně zvýší její kvalitu (a to tím, že jsme si mohli ještě před nasazením plno situací, které mohou potenciálně nastat, vyzkoušet).

    Tzn. v druhém testu nám skutečně stačí ověřit to, že při potenciálním výpadku internetu by se aplikace zachovala tak, že by chybu jednoduše zalogovala a vyjímku by „spolkla“. Test je pro nás úspěšný, protože se v dané situaci chová tak jak jsme chtěli (v reálném případě bychom mohli chtít dělat něco jiného, než jen chybu zalogovat, ale pro účely příkladu nám toto zjednodušené chování postačuje).

    Doufám, že jsem tímto aspoň trochu odpověděl na poslední dotaz?!

  3. Test č. 1 chápu – je jasný a srozumitelný. V podstatě testujeme if příkaz ve výkonné metodě business objektu. Ale test č. 2 nechápu – jak autor článku správně píše, je to simulace, ne test. Kdy ho tedy spouštět ? Když nepojede internet a spustění business classy naostro by tedy způsobilo logování, pustíme místo toho simulaci (test č. 2) s tím, že předpokládáme, že se spůstí logování a v tomto případě prohlásíme test za úspěšný ? V takovém případě ale test sám o sobě závisí ještě na okolním prostředí (stavu internetu) a sám se nemůže vyhodnotit jako úspěšný nebo neúspěšný – nebo je to úplně jinak ???

  4. Mock objekty se typicky nehodí na testování „datové vrstvy“ – tzn. pokud potřebujete testovat, zda jste složil správně SQL dotaz, tak v takovém případě vám nezbyde než se skutečně dotázat databáze a počkat si na reálné výsledky. S tím souvisí i nutná příprava testovacích dat.

    Mock objekty se hodí na testování aplikační vrstvy (viz. příklad s business objektem). Vrstva obsahující aplikační logiku obvykle pracuje s datovou vrstvou, ze které získává data pro své operace. Za předpokladu, že máme již datovou vrstvu otestovanou a funkční – můžeme si ušetřit práci při testování aplikační vrstvy použitím mocků.

    A) původní přístup:
    chci testovat aplikační objekt, ten se dotazuje datové vrstvy -> před vlastním testem musím naplnit data v databázi, tak aby, když se aplikační objekt zeptá datového, vrátily správná data. Je to dost práce, ale testuju tím vlastně najednou několik věcí (integrační test): vlastní aplikační objekt, objekty datové vrstvy, spolupráci aplikačního objektu s datovou vrstvou

    B) přístup s mocky:
    chci testovat aplikační objekt, ten se dotazuje datové vrstvy -> v testu si vytvořím virtuální mock objekty datové vrstvy a nainstruuji jim jejich chování – tzn. řeknu jim, že až se jich aplikační objekt zeptá, mají vrátit konkrétní testová data. Žádné dotazy do databáze neproběhnou. Výsledkem je daleko méně práce při psaní testů a izolovaný (unit) test, při kterém testuji jen a jen aplikační objekt. Samozřejmě musím někde jinde otestovat zvlášť datovou vrstvu, abych zamezil chybám na tomto místě. Myšlenkou je, že i když budu izolovaně psát testy na více objektů (zvlášt aplikační a zvlášt datová vrstvaj), zabere mi to méně práce a bude to lépe otestované, než kdybych se pokoušel psát pouze integrační (složité) testy. V unit testech mám totiž větší možnosti jak otestovat i různé niance daného volání, což bych při volání ob jeden objekt obtížně testoval.

  5. Moc ty mock objekty nechápu. Teď mám nějaké automatické testy, které dynamicky vytvoří SQL dotaz a vyberou něco z databáze. Já pak potřebuju zjistit, jestli ten SELECT něco vrací nebo ne. Těchto testů probíhá za sebou několik a vždy se hrabe do databáze a tahá to data, což dělá testy poněkud zdlouhavými, protože je tam hodně záznamů. Dá se pro tento problém použít nějaký mock objekt, který dobu provádění zkrátí? Já si teda myslím, že ne, protože zde se jedná o kontrolu dat a ne o kontrolu přístupu k databázi. Mám pravdu?

  6. 🙂 výsledek je lepší než jako zdroják vložený textově. Zkoušel jsem to.

    Nicméně kompletní zdrojáky je možné si stáhnout jako ZIPko, takže pokud máte zájem o detaily, originály jsou k dispozici.

  7. Zpětný odkaz: Jsem Šedý » Blog Archive » Mock testing - Potěmkinovy vesnice

  8. Ajaj, také jsem se chystal napsat něco o EasyMock. Objevil jsem je před nedávnem a dost mi zjednodušily život.
    Většinou testuji stav, ale někdy je opravdu lepší testovat procesy a na to je EasyMock jako dělaný. Našel jsem i další knihovny jako je JMock, ale přišly mi příliš komplexní pro 95% použití. A určitě musím pochválit EasyMock za žikovné použití Javy5 v v nových versích knihovny.

  9. Všechny testy ve zdrojových kódech projdou bez chyby. V metodě verify se skutečně ověřuje pouze to, co jsem uvedl v bodě #6. Konstrukce „expectLastCall().andThrow(new SenderException())“ říká přesně toto. Výsledek posledního instruovaného volání (což je v našem případě #4) bude exception, která je uvedená v parametru.

    Tzn. když je zavolána objektem tested metoda performBusinessLogic (#8) a ten uvnitř svého vykonávání zavolá na messageMocku metodu send, EasyMock místo „simulace“ vykonání vyhodí exception SenderException.

    Obdobně by se dal mock instruovat k vrácení návratové hodnoty (pokud by metoda send měla nějakou návratovou hodnotu, jako že v našem ukázkovém příkladě nemá) deklarací (uvažujme boolean):

    expectLastCall().andReturn(Boolean.TRUE)

    Pokud by stále byly nějaké pochybnosti, doporučuji stáhnout si přiložený projekt a celé si to oddebugovat. Tam nejlépe poznáte, co se kdy jak volá a s jakými výsledky.

    A propo. Děkuji za kladnou reakci – taková věc člověka vždycky potěší.

  10. Velmi pekny clanok.
    Ale mam problem s pochopenim testu c. 2. Ako to dopadne pri verify() ? Zliha to,a lebo je to OK ? Nepochopil som presne ako sa zachova konstrukcia: expectLastCall().andThrow(new SenderException) . Vysvetli mi to niekto? Vdaka.