Rychlé zápisky z The Art of Unit Testing.
Předpoklady
- Minimalizujte závislosti na globálních sdílených datech.
- Vytvářejte v kódu švy (seams), na které se testy napojí.
Konkrétně
- Nepoužívejte statické metody a singletony. Kód, který je využívá, se špatně testuje.
- Když už používáte statickou metodu, nevolejte ji přímo, ale přes pomocnou nestatickou metodu, kterou lze přepsat potomkem.
- Když už používáte singleton, oddělte od sebe samotný kontejner singletonu a jeho logiku. Tak můžete v testu přepsat logiku.
- Neinstancujte objekty v metodách s logikou. Použijte jednoduchou tovární metodu, nebo objekt předejte klientovi přes konstruktor nebo pomocnou metodu (použijte Dependency Injection).
- Spoléhejte se na rozhraní, ne na konkrétní třídy.
Best practices
- Testujte veřejný interface, ne implementaci.
- Použijte jeden assert na test.
- Pište testy nezávislé na sobě. Testy se nesmí volat navzájem, sdílet proměnné a nesmí spoléhat na pořadí.
- Testy nemají obsahovat žádnou logiku. Žádné řídící prvky typu if, switch, while, for atd.
- Testy musí být velmi jednoduché spustit a musí běžet automaticky – při buildu nebo pravidelně.
- Testy musí být spolehlivé a spravovatelné, jinak přestanou plnit svoji roli.
- Autor doporučuje testovací metody pojmenovávat podle vzoru
MethodUnderTest_TestingScenario_ExpectedResult();
Neboli podle mnemotechnické pomůcky: Když volám metodu X s Y, musí vrátit Z:
X_Y_Z();
Proc nema test obsahovat napr. for?
Rekneme, ze mam test fce, ktera pocita jestli je cislo lichy v rozmezi 0-10 (jasne, to jsem si vymyslel, ale testu, ktery maji spoustu ruznejch hodnot, ktery potrebuju otestovat je podle me mraky):
....
ts = (1,3,5,7,9,)
fs= (2,4,6,8,)
for one in ts:
self.assertTrue(one)
......
Opravdu bych mel vypisovat ten assert pro kazdou hodnotu? Na to jsem teda dost linej….
[1] Ve skutečnosti máš tolik testů jako počet položek v poli. Co když spadne jedna z položek u prostřed? Jak se dozvíme, že ty, co jsou za ní procházejí?
Od toho tu máme tzv. parametrické testy. Viz třeba TestCase z NUnit frameworku.
V tom pripade nen neni problem porovnat list ocekavanejch vs list dostanejch, ne?
Natohle je lepší použít DataProvider (PHPUnit).
[2] To, ze spadne polozka za ni je mi skoro i sumak, fail jako fail – budu se na to muset podivat tak jako tak. Jaka polozka to byla stejne vim (self.assertTrue,one,’Bububu tady to umrelo %s’%one)
Když je ti to šumák, tak pak je otázka, proč ty případy testuješ? ;)