fbpx

Snáď nepíšete všetky testy dopredu?

Bežným nedorozumením pri Test-Driven Development (TDD) je, že všetky testy pre vyvíjanú triedu treba napísať dopredu — skôr ako sa začne implementovať samotná funkcionalita. A prípadne tie testy môže vytvoriť niekto skúsenejší a implementáciu prenechá juniorovi. Takúto predstavu majú aj niektorí skúsení „unit testovači”, a preto sa im „TDD” nepáči. Týmto článkom by som chcel vysvetliť prečo je snaha o napísanie všetkých textov dopredu nesprávna. Teda, podľa mňa je nesprávna. Niekomu to možno funguje a je spokojný (poprosím vás o komentár).

V tomto článku nechcem rozoberať výhody TDD ani ako to bolo od začiatku myslené a overené praxou. Taký článok môžete nájsť tu a praktický príklad je tu. Ak s TDD ešte nemáte skúsenosti, tak si ich prečítajte skôr ako budete pokračovať v tomto článku.

Mne sa podarilo identifikovať nasledujúce dôvody, prečo by som nechcel pracovať týmto štýlom.

Code completion

Začnem s niečím ľahším. Nemusí to vadiť každému, ale mne by to vadilo.

Bez existujúceho produkčného kódu nebude fungovať code completion v IDE. Viem, že sú programátori, čo si nepotrpia na sofistikované IDE a vedia programovať efektívne aj vo Vim alebo Sublime. Podľa mňa má IDE svoju hodnotu a vie ušetriť čas a pár chýb, keď IDE doplní text samo. Ale na to potrebuje vedieť o programe viac ako len zoznam slov, ktoré sú niekde napísané.

Dizajn

Keď sú testy dané a nemenné počas implementácie komponentu, tak možnosti zmeniť dizajn komponentu za účelom jeho zlepšenia sú limitované. Testy síce neobmedzujú aké privátne metódy môžem vymyslieť, ale neumožňujú mi rozhodnúť, že čiastkový problém bude presunutý do iného komponentu, s ktorým bude vyvíjaný komponent spolupracovať. Dôvod je ten, že preddefinovaný test mi neumožňuje pridať parameter do metódy alebo konštruktora, a teda ho tam nemám ako poslať.

Toto sa netýka metód, ktoré môžem definovať na existujúcich parametroch. To ale závisí na tom, ako veľmi trvám na existujúcich testoch vopred.

Nasledujúci bod sa na tento problém pozrie z inej strany.

Zbytočné náklady

Keď počas vývoja komponentu zistím, že rozhranie nie je navrhnuté ideálne, alebo že komponent má príliš veľa zodpovednosti, je často už príliš neskoro.

Treba meniť existujúce testy, prípadne ich presúvať ku inému komponentu. To je dosť neefektívne a stojí peniaze. Ak sa rozhodnem nič nemeniť a žiť s horším dizajnom, cenu zaplatím neskôr. Väčšinou to je spôsobené práve kvôli komplikovaným testom, ktoré sa nechcú ľahko prispôsobiť zmenám.

Správne robený TDD zvyčajne privedie programátora k rozhodnutiu a zmene dizajnu oveľa skôr a často netreba prerábať nič. Jednoducho, práve vytváraný test sa napíše inak, napríklad sa použije nový mock. A produkčný kód bude nasledovať.

Tápanie v hmle

Testy napísané dopredu nemá zmysel spúšťať, lebo testovaná implementácia neexistuje. V Jave by sa ani neskompilovali. Písanie stoviek riadkov takýchto testov je nudné a únavné.

Navyše je ťažké určiť, kedy budem hotový, lebo nemám žiadnu spätnú väzbu o progrese ani o tom, či robím správnu vec. Písanie testov dopredu pripomína písanie špecifikácie, ale horším spôsobom, lebo je to kód a nie slovenská/anglická veta. Navyše je to červené more syntaktických chýb, kde nám IDE nepomôže oddeliť skutočné chyby od (ešte) nedefinovaných tried a metód.

Absurdnosť takejto činnosti je zrejmá pri porovnaní so správnym TDD, lebo pri ňom dostanem každých pár minút informáciu, že robím správnu vec:

  • test neprešiel, t.j. vie detegovať nejaký problém a nie je zbytočný
  • test prešiel, t.j. pridaná funkcionalita je správna
  • všetky testy prechádzajú, t.j. nová funkcionalita a refaktoring nič nepokazili.

Mám unit testy a teraz čo?

Povedzme, že mám tú smolu, že mi niekto pridelí úlohu s preddefinovaným testom. To ako že mi pomohol…

Čo s tým mám teraz robiť? IDE mi pomôže vygenerovať chýbajúce triedy a metódy, ale budú prázdne a všetky testy budú zlyhávať.

Vyhrniem si rukávy, pochopím prvý test, čo vlastne odo mňa chce a napíšem implementáciu metód, ktoré volá. Spustím testy, a preto že som šikovný, tak jeden test mi prejde. Ale ostatné sú stále červené. Znamená to, že moja implementácia je nesprávna alebo neúplná? Môže a nemusí. Nik nevie. Ani autor tých testov by mi na to nevedel odpovedať bez zaváhania.

Poďme ďalej. Vyberiem si ďalší test, ale zrada. Vôbec nechápem čo vlastne robí, lebo má 50 riadkov. Strávim jeho skúmaním pol hodinu a myslím, že mám predstavu, čo treba spraviť. Upravím komponent, ale test stále neprechádza. A mám dilemu — je chyba u mňa alebo je v teste? Keďže autor testu nemal možnosť si overíť, či sa nepomýlil, tak je to tak pol na pol.

A čo budem robiť, ak si autor testov nevšimol, že ani s vygenerovanými prázdnymi implementáciami sa test nedá skompilovať? Mne sa najviac pozdáva možnosť s názvom Recycle Bin.

Môže to byť ešte horšie? Môže. Čo ak test prejde, ale je v ňom chyba? To znamená, že test ma prinútil urobiť chybu v komponente.

Záver

Predpokladám, že existujú aj iné problémy, prípadne tie čo som popísal niekomu nevadia. Veľa závisí od štýlu práce a osobnosti programátora.

Môj dojem z písania kompletných testov pred implementáciou je taký, že je to horšie ako snaha o dopísanie testov dodatočne, keď už riešenie funguje. Čo teda robiť ak sa vám TDD nepozdáva, ale testy písať musíte, lebo si to projekt, na ktorom pracujete vyžaduje? Najlepšie urobíte, keď sa prikloníte ku väčšine a budete ich písať až po.

1 komentár k “Snáď nepíšete všetky testy dopredu?”

Nie je možné pridávať komentáre.