Cursus
Testen geeft je het vertrouwen dat je code doet wat je ervan verwacht. In deze tutorial leren we de basis van testgedreven ontwikkeling (TDD) met Python. We beginnen met wat achtergrond over testgedreven ontwikkeling – wat het is en waarom eerst tests schrijven helpt bij het schrijven van code. We hanteren een test-first aanpak: we schrijven eerst falende testcases voor de functionaliteit die we willen bouwen, en pas daarna de daadwerkelijke functies.
Vereisten voor deze tutorial
Voor deze tutorial heb je basiskennis van Python nodig; moet je jouw Pythonkennis opfrissen, bekijk dan deze cursus: Introduction to Python for Developers.
Een test-first aanpak helpt je om na te denken over het gewenste gedrag en de verwachte output. Je kunt in Python verschillende libraries gebruiken om te testen, zoals pytest en unnitest. Voor nu focussen we echter op het schrijven van eenvoudige testcases met native Python die valideren dat de gewenste functionaliteit de verwachte output oplevert.
We starten met een eenvoudige testcase en breiden die stap voor stap uit om verschillende scenario’s te dekken. Terwijl we onze testcases uitbreiden, kunnen we bugs of gaten in onze initiële implementatielogica ontdekken die we moeten verbeteren. Dit iteratieve proces van steeds geavanceerdere testcases schrijven, ze zien falen en dan teruggaan om onze implementatie te verbeteren, vormt de kern van testgedreven ontwikkeling met Python.
Voor deze tutorial gebruiken we DataLab, de cloudgebaseerde datanotebook van DataCamp waarmee je Python-code kunt schrijven en uitvoeren zonder lokaal iets te installeren. Laten we beginnen!
Aan de slag met DataLab
Voordat we met testgedreven ontwikkeling beginnen, verkennen we eerst DataLab en bekijken we hoe je het gebruikt zodat het je leerproces ondersteunt. Als je DataLab opent, zie je veel opties. Voor nu richten we ons op het schrijven van Python in DataLab.

Als je Python selecteert, opent het werkboek een codecel waarin je Python kunt schrijven. Dat ziet er ongeveer zo uit:

Je hebt hier een paar handige opties. Zo kun je de cel uitvoeren om output te genereren, commentaar of notities toevoegen om je leren te ondersteunen en AI gebruiken om je op weg te helpen of te deblokkeren. Je kunt ook zoveel cellen toevoegen of verwijderen als je nodig hebt. We focussen op het uitvoeren van de cel met de optie "Run". Zoals je in de onderstaande code ziet, verschijnt alle output van je code onder de cel zodra je die uitvoert.
Een korte opmerking: Als je meerdere cellen gebruikt en in de ene cel een variabele hebt gedefinieerd maar die in een andere wilt benaderen, moet je elke cel apart uitvoeren of het hele werkboek (via de knop "Run" rechtsboven in je werkboek).

Nu we de basis van DataLab onder de knie hebben, gaan we aan de slag met testgedreven ontwikkeling.
Testgedreven ontwikkeling
Testgedreven ontwikkeling betekent dat je tests voor je code schrijft vóórdat je je code schrijft. Om TDD uit te leggen, beginnen we met een eenvoudig voorbeeld: een Python-script dat getallen bij elkaar optelt. Voordat we de functie schrijven, maken we echter een test om te controleren of 1 + 1 gelijk is aan 2. Dat kun je met native Python doen, zoals hieronder getoond.
assert 1 + 1 == 2
Het sleutelwoord assert in Python wordt gebruikt om testcases te schrijven en te bevestigen dat programmacondities evalueren naar True. Zo kun je het gedrag en de output van je code valideren. Als een assert-instructie faalt, wordt een AssertionError opgegooid, wat wijst op een probleem in de code. In je DataLab-werkboek ziet dat er zo uit:

Voorbeeld 1: een eenvoudige functie testen
Laten we beginnen met de testfunctie. Open eerst een Python-bestand in DataLab. Testgedreven ontwikkeling houdt in dat je eerst een falende test schrijft. Dus schrijven we een falende test door de functie add() aan te roepen, die nog niet is gedefinieerd.
assert add(1, 1) == 2
Dit resulteert in een NameError, wat aangeeft dat er nog geen implementatie bestaat, ook wel de "rood"-stap genoemd. Je krijgt een NameError wanneer je een functie of variabele aanroept die niet is gedefinieerd.

Tijd om de functie te implementeren. Dat kunnen we doen door de functie te definiëren:
def add(num1, num2):
return
We hebben onze functie add gedefinieerd, die twee parameters aanneemt, num1 en num2. Onze functie retourneert nog niets. Kijken we of onze implementatie de test doorstaat!

We zien geen NameError meer. Maar het uitvoeren van de cel levert nog steeds een fout op! Dit keer een AssertionError. Onze test faalt dus nog steeds! Hoe komt dat? Omdat we een functie hebben gedefinieerd die nog niets retourneert.
Bij het uitvoeren van de test krijgen we een AssertionError omdat 1 + 1 met onze lege implementatie niet gelijk is aan 2. We kunnen de test laten slagen door de logica in de functie correct te implementeren.

Je ziet het groene bolletje in de hoek van de cel. Dat geeft aan dat je code geldig is en slaagt wanneer je de cel uitvoert. Voorheen was het rood met een runtime-fout en werd het type fout onder de cel weergegeven. Deze functie is handig voor het debuggen van je code in DataLab.
Je hebt nu je eerste test in Python geschreven met testgedreven ontwikkeling. Goed gedaan! We gaan nu verder met het uitbreiden van onze tests en nadenken over het afvangen van mogelijke fouten waardoor onze functie kan falen of niet de verwachte output oplevert.
Voorbeeld 2: meerdere testcases
Testen met slechts één invoerwaarde onthult vaak geen potentiële fouten. Bugs kunnen zich makkelijk verbergen, zeker als je functie afhankelijk is van variabele gebruikersinvoer of externe logica. Hoe testen we een functie grondig tegen meerdere waarden?
Wat als er bijvoorbeeld een onjuist datatype aan de functie wordt doorgegeven? Je zou Python-testframeworks kunnen gebruiken, maar laten we nu basis-Python gebruiken. Eerst definieer ik een lijst met invoer-dictionaries om verschillende gebruiksscenario’s te simuleren:
test_cases = [
{"num1": 1, "num2": 3, "expected": 4},
{"num1": 1, "num2": "invalid", "expected": "Error: num2 must be a number"},
{"num1": [1,2,3], "num2": 2, "expected": "Error: num1 must be a number"},
{"num1": -1, "num2": 1, "expected": 0},
{"num1": 3.5, "num2": 2.5, "expected": 6.0},
{"num1": 100, "num2": 200, "expected": 300}
]
De bovenstaande code toont invoer voor de functie met de bijbehorende verwachte outputs. We moeten onze test echter updaten om door deze testcases te itereren. We kunnen elk dictionary in de lijst valideren door de assert in een for-lus te plaatsen.
for test in test_cases:
assert add(test["num1"], test["num2"]) == test["expected"]
Aangezien de functie ongewijzigd is, verwachten we dat deze test slaagt of faalt? En welke fout kan optreden?

De test gooit een TypeError, omdat we niet-nummerieke invoer nog niet hebben afgehandeld; wat als er een string of boolean wordt doorgegeven in plaats van een int? We kunnen de functie updaten om deze gevallen op te vangen! We kunnen een aangepast bericht retourneren bij ongeldige types door te controleren of de invoervariabele een integer of float is.
def add(num1, num2):
if type(num1) is not int and type(num1) is not float:
return "Error: num1 must be a number"
elif type(num2) is not int and type(num2) is not float:
return "Error: num2 must be a number"
else:
return num1 + num2
Als we onze tests opnieuw uitvoeren, krijgen we geen fouten meer, dus onze tests zijn geslaagd. We zien nu ook een groen bolletje dat aangeeft dat we geslaagde tests hebben geïmplementeerd. Goed gedaan!

Tot slot
In deze tutorial hebben we de basis van testgedreven ontwikkeling in Python behandeld met DataLab. DataLab biedt een cloud-IDE waarmee je Python-code kunt schrijven en uitvoeren zonder lokale installaties. Tests valideren het gedrag van code en vangen fouten vroegtijdig. Assert-statements controleren voorwaarden en genereren uitzonderingen bij falen.
Je kunt meer testcases verkennen en je eigen tests gaan schrijven in DataLab! Wil je meer leren over testen in Python, bekijk dan onze DataCamp-cursus - Introduction to Testing in Python.
Amina is een stagiair contentontwikkeling bij Datacamp. Met een achtergrond in architectuur en onderwijs maakte ze een carrièreswitch naar softwareontwikkeling, beginnend met JavaScript; inmiddels richt ze zich op Python.

