DevOpsProperty Based Testing

Property Based Testing (PBT)  is een test-soort uit de “Random Testing”, waarin getest wordt met random input data. PBT is een unit-test techniek, die wat verder reikt dan de standaard setup-run-verify test. Maar een PBT is niet zo heel erg veel moeilijker om te schrijven.

Unit test

Unit test

Bij gewone unit-testen, maak je -simpel gezegd- vijf unit tests; een sunny day scenario, rainy day scenario, en een onder, op, en boven de grenswaarde test. Dat is toch wel een beetje gebaseerd op voorkennis van de code of functionaliteit, en bugs bestaan meestal op de plekken waar je juist niet kijkt.

Als er door een bug of change een grenswaarde ontstaat in bijvoorbeeld het sunny day gebied, dan wordt die bug niet zo snel ontdekt met gewone unit-tests. Voor simpele code zal dat niet zo’n groot probleem zijn omdat je die bug waarschijnlijk wel ontdekt in een peer-code-review of andere tests. Maar als het aantal parameters groeit en de code complexer wordt, dan kan het wel eens lastig worden om bepaalde bugs te vinden.

Property Based Testing

Met Property Based Testing schiet je random waarden af op de functie die je wilt testen en controleer je “Properties” die altijd gelden. Ongeacht de input waarden. Dat zijn dus de “Properties” in PBT.

Maar wat zijn altijd geldende eigenschappen? Neem een heel simpel voorbeeld met een optel functie. Bij alle waarden van a en b, geldt altijd: (a+b) == (b+a), en (a+0) == a. Dit zijn twee eigenschappen die je met PBT kunt testen.

Bij een klant hadden we een real-world scenario. In een systeem werd data van een Zend-functie naar een Ontvang-functie gestuurd via het UDP protocol. De Zend functie werd aangeroepen met een data-class en de ontvangst functie moest dezelfde data-class produceren na ontvangst. Tussendoor werd de data ook nog heen en weer geconverteerd, omdat een byte-array werd gebruikt voor UDP transport.

Na een wijziging wilden we graag weten of het alles goed werkte. We hebben het netwerk transport uitgeschakeld met mocking en de Zend en Ontvang functies direct aan elkaar geknoopt.

Onze “Property” in PBT was de eigenschap, dat de output van de Ontvang-functie, altijd hetzelfde moest zijn als de input van de Zend-functie. Beide functies zijn immers elkaars inverse.

Automatisch testen

Die Property hebben we dan ook duizenden keren doorgetest met random input voor de Zend functie. 100.000 keer doortesten duurde maar 2 minuten, op een gewone ontwikkel PC. Toen die test eenmaal geslaagd was, hadden we er zeer veel vertrouwen in dat onze wijziging prima werkte.

FsCheck

We hebben nuget library “FsCheck” gebruikt voor PBT. Dit is een library die veel wordt gebruikt in de F# wereld, maar de laatste tijd wordt deze library ook steeds populairder in de C# wereld.

FsCheck biedt random generators. Die werken op basis van reflection, dus je kunt er ook enums mee produceren. En je kunt de generator output verder verfijnen met onder- en bovengrenzen. FsCheck biedt ook een “shrink” functionaliteit. Als door een bug, de Property ongeldig is voor een bepaalde waardes, dan wordt het random domein gekrompen. Op die manier probeert FsCheck te ontdekken bij welke grenswaarde het misgaat, en dat wordt ook gelogd. Dus met shrink bouw je een unit test die zelf opspoort waar het fout gaat. Dat is best handig!

Frank Joppe, Developer