Image

Unit testen met PyTest

Hoe bouw je betrouwbare en beheersbare code?

Tim
23-06-2022

Betrouwbare en beheersbare code zorgen voor besparing van tijd, kosten, en het voorkomen van grote fouten. In het software-landschap worden velen testen gebruikt, en deze dragen bij aan die betrouw- en beheersbaarheid. Het testen van alles wat je ontwikkelt, bespaart aan het eind van de rit veel tijd en geld. Hoe hoog die besparing is hangt natuurlijk af van de waarde van de output en de kosten die gemoeid zijn met de continue ontwikkeling. In deze blog geven we een introductie in PyTest, een tool voor het doen van unit tests, om daarbij te helpen.

Maar hoe en wat moet ik testen dan, vraagt u zich inmiddels af? Nou.., daar is geen kort of simpel antwoord op. Testen kan namelijk op allerlei manieren. Zo zijn er de unit tests, integration tests, functional tests, end-to-end tests, performance tests en user-acceptance tests. Vervolgens kan dit ook nog worden opgesplitst naar handmatige en geautomatiseerde tests. En zo kunnen we even doorgaan... Daarbij komt vaak kijken dat software testen wordt gezien als een noodzakelijk kwaad vanuit de business en niet als een mogelijkheid om betrouw- en beheersbaarheid te verhogen. Gezien de grote waarde van testen voor zowel de business als ontwikkelaars wordt er in deze blog een introductie gegeven. De focus hierbij is op het laagdrempelige (lage instapkosten) unit testen, en dan specifiek in Python als veelgebruikte programmeertaal. Er zal hierbij gebruikt worden gemaakt van PyTest.

De onderwerpen die langs zullen komen zijn:

  • Waarom en wat is unit testen?
  • De basis van PyTest
  • Valideren van fouten die je verwacht
  • Testen met verschillende input waardes
Benodigdheden

Waarom en wat is unit testen?

In dit eerste deel zal worden beschreven wat unit testen inhoud en welke voordelen dit biedt. Hierdoor wordt ook duidelijk wat de voordelen zijn van dit soort processen in controleerbare code vast te leggen ten opzichte van de oncontroleerbare processen die vaak gebaseerd zijn op Excel bestanden.

Unit testen

Bij unit tests worden de individuele componenten (units) van een stuk software getest. Hiermee kan worden gecontroleerd of de code doet wat er van verwacht wordt. Er wordt dus (verschillende) input gedefinieerd met een bijbehorende verwachte output. Vervolgens kan de output van de component (met input) vergeleken worden met de verwachte output.

De focus moet zijn om één specifiek ding te testen, hiermee wordt de ontwikkelaar ook gedwongen om zijn componenten maar één specifieke taak te laten uitvoeren. Hierdoor ontstaat ook meteen schone en leesbare code (#win-win).

In sommige gevallen worden componenten ook gebouwd door te beginnen met het maken van een test. Dit wordt ook wel 'test-driven-development' genoemd. Dit wordt gedaan omdat in de test de verwachte output van een component wordt gedefinieerd. Vervolgens kan de component gebouwd worden totdat de test slaagt. Hiermee wordt de ontwikkelaar ook gedwongen om eerst goed na te denken over de verwachte uitkomst, in plaats van vol enthousiasme te gaan coderen zonder plan.

Voordelen op een rij

Naast de eerder benoemde voordelen gericht op de ontwikkelaar zijn er minstens net zo belangrijke voordelen voor de business. Door het gebruik van testen wordt niet alleen de kwaliteit van de code verhoogd maar ook die van het algehele product. Het wordt betrouwbaarder, doordat meer fouten al tijdens de ontwikkeling worden afgevangen. Hiermee zijn er ook minder risico's met het gebruik van het product. Daarnaast is er een kleinere kans dat er fouten of issues in een later stadium opgelost moet worden. Dit zorgt altijd voor minder kosten. In de toekomst zullen eventuele doorontwikkelingen beter kunnen worden ingeschat, minder tijd in beslag nemen en dus tot een tevreden gebruiker leiden.

  • Verhoogt kwaliteit van code en product
  • Verlaagt risico's
  • Verhoogt tevredenheid van ontwikkelaar en gebruiker
  • Verlaagt kosten
  • Verlaagt totale doorlooptijd

De basis van PyTest

Een van de mogelijkheden om unit tests te gebruiken in Python is door middel van de package PyTest. Hierbij een korte introductie tot PyTest. Er wordt gebruik gemaakt van een functie en er worden twee testen uitgevoerd:

  • Functie (unit) die getest moet worden (calculate())
  • Test die faalt (test_failing_answer()).
  • Test die niet faalt (test_successful_answer())
Code
pytest_intro
Code ter introductie van PyTest

Dit zijn simpele tests die twee getallen met elkaar vergelijken, met PyTest kan je echter ook complexere tests uitvoeren. Deze zijn verder terug te vinden in de documentatie.

Valideren van fouten die je verwacht

In de introductie bouwden we tests waarbij de code succesvol draait en de uitkomst gecontroleerd wordt. Tijdens het ontwikkelen komen er ook situaties voor waarbij we bewust willen dat de code NIET succesvol draait. In Python zorgt dit voor errors die de code stopt, en hierdoor kan de assert niet plaats vinden. Gelukkig biedt PyTest ook de mogelijkheid om te testen of de code juist een error geeft bij bijvoorbeeld een verkeerde input.

Code
pytest_exception
Testen voor fouten in PyTest

Hier is te zien hoe een fout afgevangen kan worden. Er kan zelfs een stap verder gegaan worden door ook gebruik te maken van zelfgedefinieerde fouten. Hierdoor kan je de tests nog specifieker inrichten.

Testen met verschillende input waardes

Eerder is al benoemd dat je de functies wil kunnen testen met verschillende input waardes. De functie moet namelijk de juiste output geven voor verschillende input. PyTest heeft ervoor gezorgd dat er niet steeds een nieuwe test geschreven hoeft te worden voor iedere input, of een omslachtige for-loop om de test heen gebouwd hoeft te worden. PyTest biedt namelijk de @pytest.mark.parametrize decorator. De werking hiervan zie je hieronder.

Code

Invoer van de parametrize functie is:

  • De namen van de input variabelen, in de vorm van een str gescheiden door een komma.
  • Een list van tuples met daarin de corresponderende waardes die je als input mee wil geven aan de test.

In dit geval worden er twee input variabelen meegegeven die ook input variabelen zijn van de functie die getest wordt. De 3e input van de test is de waarde die verwacht wordt op basis van de input waardes.

pytest_params
Testen met verschillende input waardes in PyTest

In de output is nu ook te zien dat er twee tests succesvol zijn afgerond, terwijl er maar een test gedefinieerd is. De twee verschillende inputs zorgen ervoor dat dit gezien wordt als twee testen.

Ten slotte

De betrouw- en beheersbaarheid van de code kan verhoogd worden door middel van testen en daarmee tot de verhoging van kwaliteit, verlaging van kosten en verlaging van risico's. In deze blog is er een introductie gedaan in de wereld van het testen om te laten zien dat het allemaal zo eng niet is. Er is gefocust op het laagdrempelige unit testen en hoe dit te kunnen implementeren in een Python project met PyTest. Hopelijk ben je overtuigd van het nut van testen voor de business en/of heb je een mooie introductie tot PyTest weten te krijgen.
Start met testen en verhoog die betrouw- en beheersbaarheid!

Vond je dit artikel interessant?

divider graphic