Cursus
Unit testing is een testmethode voor software waarbij individuele eenheden van broncode aan verschillende tests worden onderworpen om te bepalen of ze geschikt zijn voor gebruik. Het beoordeelt en waarborgt de kwaliteit van je code.
Meestal, wanneer het ontwikkelproces voltooid is, codeert de developer criteria—of resultaten waarvan bekend is dat ze praktisch en nuttig kunnen zijn—in het testscript om de correctheid van een bepaalde unit te verifiëren. Tijdens het uitvoeren van testcases registreren verschillende frameworks tests die voor een criterium zakken en rapporteren die in een samenvatting.
Van developers wordt verwacht dat ze geautomatiseerde test scripts schrijven, zodat elk onderdeel of elke unit aan het ontwerp voldoet en zich gedraagt zoals verwacht.
Unit testen in Python
Hoewel handmatig tests schrijven voor je code zeker een tijdrovende en monotone taak is, maakt Python’s ingebouwde unit testing-framework het leven een stuk makkelijker.
Het unit test-framework in Python heet unittest en wordt standaard met Python meegeleverd.
Unit testing maakt je code toekomstbestendig, omdat je anticipeert op gevallen waarin je code mogelijk faalt of een bug veroorzaakt. Hoewel je niet alle gevallen kunt voorspellen, pak je er toch de meeste aan.
Een unit kan in verschillende categorieën worden ingedeeld:
- Een volledige module,
- Een individuele functie,
- Een complete interface zoals een class of een methode.
De beste manier om unit tests voor je code te schrijven, is om te beginnen met de kleinst mogelijke testbare unit van je code, vervolgens door te gaan naar andere units en te bekijken hoe die kleinste unit met andere units samenwerkt. Zo kun je stap voor stap een uitgebreide unit test voor je applicaties opbouwen.
Python’s unit testing-framework is geïnspireerd op Java’s JUnit en heeft vergelijkbare features als de belangrijkste unit testing-frameworks in andere talen. Python’s unit testing-framework biedt verschillende features, waaronder:
- Testautomatisering
- Het delen van setup- en afsluitcode voor tests
- Tests bundelen in collecties
- Onafhankelijkheid van de tests ten opzichte van het rapportageframework
Laten we nu een voorbeeld nemen om te begrijpen waarom je unit tests voor je code nodig hebt.
Aan de slag met Python unittest
Hieronder hebben we de stappen uiteengezet die je nodig hebt om Python’s unittest framework te gebruiken
Een kubusfunctie maken
Laten we code schrijven om het volume van een kubus in Python te berekenen
def cuboid_volume(l):
return (l*l*l)
length = [2,1.1, -2.5, 2j, 'two']
for i in range(len(length)):
print ("The volume of cuboid:",cuboid_volume(length[i]))
The volume of cuboid: 8
The volume of cuboid: 1.3310000000000004
The volume of cuboid: -15.625
The volume of cuboid: (-0-8j)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-7-67e1c37a435f> in <module>
1 for i in range(len(length)):
----> 2 print ("The volume of cuboid:",cuboid_volume(length[i]))
<ipython-input-2-f50464fd88da> in cuboid_volume(l)
1 def cuboid_volume(l):
----> 2 return (l*l*l)
TypeError: can't multiply sequence by non-int of type 'str'
Resultaatanalyse
De bovenstaande output geeft je een idee van het belang van een unit test voor je code. Er zijn drie dingen die zeker onjuist zijn in de bovenstaande code:
- Ten eerste: het volume van de kubus is negatief,
- Ten tweede: het volume van de kubus is een complex getal,
- Tot slot: de code resulteert in een
TypeErroromdat je een string, die geen int is, niet kunt vermenigvuldigen.
Het derde probleem gaf gelukkig een error, terwijl het eerste en tweede toch slaagden, ook al kan het volume van de kubus niet negatief of een complex getal zijn.
Unit tests worden meestal als aparte code in een ander bestand geschreven, en er kunnen verschillende naamgevingsconventies worden gevolgd. Je kunt de naam van het unit test-bestand ofwel schrijven als de naam van de code/unit + test gescheiden door een underscore, of test + naam van de code/unit gescheiden door een underscore.
Stel dat de bestandsnaam van de bovenstaande code cuboid_volume.py is; dan zou je unit test-code cuboid_volume_test.py kunnen heten
Zonder verder oponthoud schrijven we de unit test voor de bovenstaande code.
assertAlmostEqual gebruiken
Maak eerst een Python-bestand met de naam volume_cuboid.py met de code om het volume te berekenen, en een tweede met de naam test_volume_cuboid.py met de unit test-code.
import unittest
De class TestCuboid erft van de module unittest, en in deze class definieer je verschillende methodes die je wil dat je unit test controleert met je functie cuboid_volume.
De eerste functie die je definieert is test_volume, die controleert of de output van cuboid_volume gelijk is aan wat je verwacht. Hiervoor gebruik je de methode assertAlmostEqual.
Test 1
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),0)
self.assertAlmostEqual(cuboid_volume(5.5),166.375)

Laten we het bovenstaande script uitvoeren. Je draait de unittest module als script door -m op te geven bij het uitvoeren.
!python -m unittest test_volume_cuboid.py
Output:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
Top! Je eerste unit test werkt.
De test is succesvol uitgevoerd en gaf OK terug, wat betekent dat de functie cuboid_volume werkt zoals je verwacht.
Test 2
Laten we bekijken wat er gebeurt wanneer een van de assertAlmostEqual-aanroepen faalt.

Let op dat de laatste assert-instructie is aangepast.
!python -m unittest test_volume_cuboid.py
Output:
F
======================================================================
FAIL: test_volume (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 15, in test_volume
self.assertAlmostEqual(cuboid_volume(5.5),0)
AssertionError: 166.375 != 0 within 7 places (166.375 difference)
----------------------------------------------------------------------
Ran 1 test in 0.001s
FAILED (failures=1)
Uit de bovenstaande output kun je zien dat de laatste assert leidde tot een AssertionError en dus tot een unit test-fout. Python’s unittest-module laat de reden van de fout zien, samen met het aantal mislukkingen in je code.
assertRaises gebruiken
Laten we nu een andere assert-methode verkennen, namelijk assertRaises, die je helpt te controleren of je functie cuboid_volume de invoerwaarden correct afhandelt.
Stel dat je wil testen of je functie cuboid_volume het type invoer afhandelt. Als je bijvoorbeeld een string doorgeeft, behandelt de functie die invoer dan als een exceptie of met een if-voorwaarde? De lengte van de kubus kan immers nooit een string zijn.

!python -m unittest test_volume_cuboid.py
Output:
F.
======================================================================
FAIL: test_input_value (test_volume_cuboid.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "C:\Users\hda3kor\Documents\Unit_Testing_Python\test_volume_cuboid.py", line 17, in test_input_value
self.assertRaises(TypeError, cuboid_volume, True)
AssertionError: TypeError not raised by cuboid_volume
----------------------------------------------------------------------
Ran 2 tests in 0.001s
FAILED (failures=1)
Mooi! Uit de bovenstaande output blijkt duidelijk dat je code volume_cuboid.py de doorgegeven invoer niet goed afhandelt.
De kubusfunctie aanpassen
Laten we een voorwaarde toevoegen in volume_cuboid.py om te controleren of de invoer of lengte van de kubus een boolean of een string is en dan een error opwerpen.

!python -m unittest test_volume_cuboid.py
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.001s
OK
Het Python-testscript uitvoeren in JupyterLab
Laten we het testscript nu binnen JupyterLab draaien. Hiervoor definieer je eerst het testscript in JupyterLab, zoals hieronder getoond.
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""
from volume_cuboid import *
import unittest
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)
def test_input_value(self):
self.assertRaises(TypeError, cuboid_volume, True)
Vervolgens gebruik je de methode unittest.main() om het testscript uit te voeren. Je kunt verschillende argumenten aan de onderstaande methode doorgeven, waaronder het verbosity-niveau.
Laten we met verschillende verbosity-niveaus experimenteren en zien hoe de uitvoerbeschrijving verandert.
Verbosity 0
unittest.main(argv=[''],verbosity=0, exit=False)
Output:
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
<unittest.main.TestProgram at 0x1de02774348>
Verbosity 1
unittest.main(argv=[''],verbosity=1, exit=False)
Output:
..
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgram at 0x1de027a1cc8>
Verbosity 2
unittest.main(argv=[''],verbosity=2, exit=False)
Output:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... ok
----------------------------------------------------------------------
Ran 2 tests in 0.002s
OK
<unittest.main.TestProgram at 0x1de027a8308>
De AssertionError visualiseren
Tot slot passen we de laatste assertAlmostEqual in de methode test_volume aan en analyseren we hoe verbosity-niveau 2 de mislukking van de methode laat zien.
# -*- coding: utf-8 -*-
"""
Created on Sat Apr 25 20:16:58 2020
@author: Aditya
"""
from volume_cuboid import *
import unittest
class TestCuboid(unittest.TestCase):
def test_volume(self):
self.assertAlmostEqual(cuboid_volume(2),8)
self.assertAlmostEqual(cuboid_volume(1),1)
self.assertAlmostEqual(cuboid_volume(0),1)
def test_input_value(self):
self.assertRaises(TypeError, cuboid_volume, True)
unittest.main(argv=[''],verbosity=2, exit=False)
Output:
test_input_value (__main__.TestCuboid) ... ok
test_volume (__main__.TestCuboid) ... FAIL
======================================================================
FAIL: test_volume (__main__.TestCuboid)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<ipython-input-28-46ad33b909ee>", line 14, in test_volume
self.assertAlmostEqual(cuboid_volume(0),1)
AssertionError: 0 != 1 within 7 places (1 difference)
----------------------------------------------------------------------
Ran 2 tests in 0.003s
FAILED (failures=1)
<unittest.main.TestProgram at 0x1de027b5448>
Samenvatting
Uit de bovenstaande outputs kun je het volgende concluderen:
- Verbosity-niveau 0 toont alleen hoeveel tests er zijn uitgevoerd (d.w.z. 2) en de tijd die dat kostte,
- Verbosity-niveau 1 voegt twee puntjes toe .. die aangeven dat er twee tests zijn uitgevoerd,
- Verbosity-niveau 2 toont de gedetailleerde methodenamen die zijn uitgevoerd, samen met hun status
OKofFAIL.
Beschikbare unittest-assert-methodes
Er zijn veel assert-methodes in de unittest-module van Python die je voor testdoeleinden kunt benutten.
Veelgebruikte assert-methodes

Bron: unittest-documentatie
Productiecontroles
Met de volgende methodes kun je controleren op het ontstaan van exceptions, waarschuwingen en logberichten.

Bron: unittest-documentatie
Taakspecifieke methodes

Bron: unittest-documentatie
Wil je de assert-methodes in detail leren kennen, bekijk dan Python’s officiële documentatie.
Je kunt er ook over leren met behulp van de module Pydoc, vergelijkbaar met de functie help in Python. Hieronder zie je hoe je de Pydoc-module kunt gebruiken om de documentatie van de methode assertCountEqual te lezen.
!python -m pydoc unittest.TestCase.assertCountEqual
Output:
Help on function assertCountEqual in unittest.TestCase:
unittest.TestCase.assertCountEqual = assertCountEqual(self, first, second, msg=None)
An unordered sequence comparison asserting that the same elements,
regardless of order. If the same element occurs more than once,
it verifies that the elements occur the same number of times.
self.assertEqual(Counter(list(first)),
Counter(list(second)))
Example:
- [0, 1, 1] and [1, 0, 1] compare equal.
- [0, 0, 1] and [0, 1] compare unequal.
Conclusie
Deze tutorial was een basisintroductie tot unit testing in Python en het belang ervan voor developers. Een goede oefening voor jou is om een unit test-module te schrijven voor een van je eerdere projecten. Dat geeft je praktijkervaring met het schrijven van unit tests. Verken ook de overige assert-methodes. Je kunt meer lezen over unit testing met onze Pytest-tutorial.
Als je net begint met Python en meer wilt leren, volg dan onze Introduction to Data Science in Python-cursus.
Als gecertificeerd data scientist haal ik met passie het maximale uit de nieuwste technologie om innovatieve machinelearning-toepassingen te bouwen. Met een sterke achtergrond in spraakherkenning, data-analyse en -rapportage, MLOps, conversationele AI en NLP heb ik mijn vaardigheden aangescherpt in het ontwikkelen van intelligente systemen die echt impact maken. Naast mijn technische expertise ben ik ook een sterke communicator met een talent om complexe concepten terug te brengen tot heldere, beknopte taal. Daardoor ben ik uitgegroeid tot een veelgelezen blogger over data science, waar ik mijn inzichten en ervaringen deel met een groeiende community van data-professionals. Op dit moment richt ik me op contentcreatie en redactie, waarbij ik met large language models werk aan krachtige en aansprekende content die zowel bedrijven als individuen helpt het beste uit hun data te halen.

