Er is een wijdverspreid misverstand over wat een "unit" precies is. Als je het boek Test Driven Development by Example van Kent Beck leest, dan zie je overduidelijk dat het niet gaat om het testen van een unit of structure (bijvoorbeeld een class of functie), maar om het testen van een unit of behaviour!
Daar komt ook nog eens een veelgeziene misinterpretatie van de i (isolated/independent) van de FIRST principles bij, namelijk dat je met unit tests een deel van je code (een unit of structure) in isolatie moet testen. Alleen daar gaat het helemaal niet om. Het gaat er bij isolated/independent om dat unit test onafhankelijk
van elkaar moeten zijn. Het draaien van test1 mag geen invloed hebben op het al-dan-niet slagen van test2.
Één van de grote voordelen van unit testing in het algemeen en test driven development in het bijzonder is dat de tests een veilig vangnet vormen voor als je het design van je productiecode wilt refactoren. Het idee is dat je veilig kunt refactoren en dat je tests je helpen om zeker te weten dat je refactorings geen ongewenste bijeffecten hebben.
De mate waarin je vrij kunt refactoren is daarbij wel afhankelijk van de mate waarin je tests gekoppeld zijn aan het design van je productiecode. Hoe meer van dat soort "coupling", hoe meer unit tests refactoring moeilijk maken. Hoe losser die coupling, hoe makkelijker het refactoren wordt.
Het probleem met mocking is dat je daarmee een behoorlijk sterke dependency legt tussen unit tests en de structuur van je productiecode. Mocks maken het dus vaak (niet altijd) moeilijker om te refactoren, omdat je bij wijzigingen in je design ook elke keer je tests moet aanpassen.
De oplossing is om meer in units of behaviour te denken en om in je unit tests zo veel mogelijk gebruik te maken van stabiele interfaces binnen je productiecode. Het effect van deze manier van werken ten opzichte van de benadering van het testen van units of structure in isolatie is beter onderhoudbare code:
- Refactoring is makkelijker
- Je schrijft vaak minder unit tests, zonder op testdekking in te leveren
- Unit tests lezen als executable specifications en helpen om de productiecode te begrijpen
Stel niet uit tot morgen wat je vandaag nog tot morgen kunt uitstellen...