Inhoudsopgave
“Ik test handmatig” is een uitspraak die elke developer wel eens doet, maar zelden vol kan houden naarmate een codebase groeit. Handmatig testen schaalt niet — elke nieuwe feature vergroot het oppervlak dat je moet controleren, en menselijke aandacht is eindig en feilbaar. Geautomatiseerde tests zijn geen luxe voor grote teams met veel tijd, maar een basishygiëne die je juist tijd bespaart. De vraag is niet óf je moet testen, maar hoe je het zo effectief mogelijk aanpakt.
De testpiramide
De testpiramide is het meest gebruikte model om teststrategieën te structureren. Onderaan staan unit tests — snel, geïsoleerd en in grote aantallen. In het midden zitten integratietests die controleren of onderdelen correct samenwerken. Bovenaan staan end-to-end tests die het volledige systeem doorlopen vanuit het perspectief van de gebruiker. Hoe hoger in de piramide, hoe langzamer en duurder de test. Een gezonde testsuite heeft veel unit tests, een redelijk aantal integratietests en een beperkt aantal end-to-end tests — niet andersom.
Unit tests schrijven die waarde hebben
Niet elke unit test is een goede unit test. Een test die alleen maar controleert of een functie zijn eigen implementatie nabootst, is waardeloos. Goede unit tests controleren gedrag, niet implementatie. Ze testen wat een functie teruggeeft gegeven bepaalde input, niet hoe hij dat intern berekent. Houd tests klein en gefocust, geef ze beschrijvende namen en zorg dat ze onafhankelijk van elkaar draaien. Een test die alleen faalt als er ook echt iets mis is, is een test die je kunt vertrouwen.
Test driven development
Test Driven Development (TDD) draait de volgorde om: je schrijft eerst de test, dan de implementatie. Rood, groen, refactor. De test faalt eerst omdat de code nog niet bestaat, dan schrijf je de minimale code om hem te laten slagen, en daarna refactor je. TDD dwingt je na te denken over het gewenste gedrag voordat je begint met bouwen en resulteert in code die van nature testbaar is. Het voelt in het begin traag, maar wie het een tijdje volhoudt merkt dat het debuggen drastisch vermindert en het ontwerp van de code verbetert.
Mocking en isolatie
Integratietests en unit tests hebben verschillende behoeften als het gaat om externe afhankelijkheden zoals databases, APIs of bestandssystemen. In unit tests wil je die afhankelijkheden vervangen door mocks — nep-implementaties die voorspelbaar gedrag vertonen zodat je de eenheid die je test volledig isoleert. Frameworks zoals Jest, Mockito en unittest.mock maken dat eenvoudig. Overdrijf echter niet met mocking: als je alles mockt test je niets meer echt. Gebruik mocks voor externe systemen, maar laat je eigen logica zo veel mogelijk ongemockt.
Tests als vangnet bij refactoren
Een van de grootste voordelen van een goede testsuit is het vertrouwen dat hij geeft bij refactoren. Als je code wil verbeteren zonder het gedrag te veranderen, zijn tests het enige objectieve bewijs dat je niets hebt gebroken. Zonder tests is refactoren gokken — met tests is het een gecontroleerde operatie. Zorg daarom dat je testsuit snel genoeg is om regelmatig te draaien, integreer hem in je CI-pipeline en behandel falende tests nooit als iets wat je even uitschakelt. Een test die je uitzet omdat hij lastig is, was waarschijnlijk de belangrijkste.