I když si myslím, že mám s unit testy dost zkušeností, stále ještě mě dokáží dost překvapit. Kromě toho, že se překvapuji tím jak často je „zapomínám“ psát, překvapují mě většinou pozitivně. Zrovna nedávno mě překvapily znovu.
Psal jsem program, který mimo jiné prohledává adresář na disku, poté nalezené soubory zpracovává, přesouvá jinam, archivuje, vytváří adresáře a dělá jiné psí kusy se souborovým systémem. Tuto část jsem chtěl otestovat. Ale jak na to? Jedno z dogmat unit testů nám říká, že unit test nepracuje se souborovým systémem. Kdybych použil třídu java.io.File
, nemohl bych napsat unit test, protože tato třída na disk přistupuje. Řešení je jednoduché – musel jsem abstrahovat přístup na souborový systém. Přiznávám, že se mi do toho moc nechtělo. Abstrahovat přístup, který je už abstrahován jazykem mi přišlo zbytečné. Ale nakonec jsem se odhodlal a napsal jsem si rozhraní FileSystemDao
|
Uznávám, že nazývat to DAO je trochu zavádějící, ale podle mě to vystihuje co jsem jím chtěl vyjádřit.
Skvělé, mám DAO pro přístup do souborového systému, mohu si vytvořit mock a vesele unit testovat. Nápad je to dobrý, nicméně má své vady na kráse. Výsledný test je neuvěřitelně nepřehledný. Vytvořit mock, který simuluje stav souborového systému před operací a po ní je docela náročné. Navíc jsem přišel na to, že tento test je až moc odtržen od reality. Neupozorní nás na to, že například kopírujeme soubor do neexistujícího adresáře. Při každé změně aplikace, se navíc testy musely dost pracně aktualizovat. Vydržel jsem to den a pak jsem tyto testy smazal. Kvůli pracnosti jsem zavrhl i myšlenku na to, že bych souborový systém simuloval v paměti, například pomocí nějakého stromu. Poslechl jsem Testuvia, který říká
Nezabředni do unit testového dogmatu
Napsal jsem normální funkční test, který využívá souborový systém. S tímto testem jsem nadmíru spokojen. Probíhá velmi rychle, hledá mi chyby a není s ním žádná práce. Navíc když se na něj podívám, krásně popisuje to co má testovaný kus kódu dělat.
Ale co se stalo s rozhraním FileSystemDao? Vypadá to, že teď už není potřeba. Opak je pravdou. Hodně se osvědčilo. Je v něm kód pracující se souborovým systémem soustředěný na jediném místě. Když jsem byl donucen změnit kód pro vyhledávání souborů pomocí masky, změnil jsem ho na jediném místě. Když se přišlo na to, že před každým přesouváním souboru musím vytvořit cílový adresář, zařídil jsem to změnou na jediném místě. Když se ukázalo, že je toto řešení neefektivní, opravil jsem to pouze v implementaci tohoto rozhraní.
Vidíme tedy, že mě potřeba napsat unit test donutila abstrahovat něco co by mě vůbec abstrahovat nenapadlo. Ono totiž na první pohled není o moc lepší psát fileSystemDao.moveFile(source, dest)
než source.renameTo(dest)
. Teprve čas ukázal, že ta první, na první pohled nesmyslná varianta má své výhody. Nezbývá mi než si zopakovat starou pravdu
Unit testy si vynucují dobrý návrh.