Expliciete versus impliciete definities van correct
Geautomatiseerde tests dwingen ons om correct op te schrijven in de vorm van assertions in code. Elke geautomatiseerde test heeft een of meer assertions. Deze geschreven assertions zijn een expliciete definitie van correct.
Correct wordt minder vaak opgeschreven wanneer testers handmatig testen. Hier wordt vaak gestopt bij requirements. Dit betekent natuurlijk niet dat er helemaal geen definitie is. In plaats van het opschrijven, gebruikt de tester een impliciete definitie van correct. Impliciete definities zouden eigenlijk opgeschreven moeten worden zodat ze expliciet en – belangrijker -herbruikbaar worden. Ik erken echter ook dat dat niet altijd praktisch is.
Hoe definieer je correct
Er zijn twee fundamentele manieren om correct te definiëren: voorbeelden en regels. Deze zjjn fundamenteel omdat ze niet beschreven kunnen worden als iets anders dan zichzelf. Ze zijn de meest basale vorm van correct definiëren die ik ken. De omschrijvingen hieronder zijn niet heel gedetailleerd, maar zijn goed genoeg om een grof idee te geven.
Voorbeeld
Een voorbeeld heeft een specifieke situatie (= state en input) en correct resultaat (= output of side effect) nodig voor een specifieke Subject Under Test (SUT). Het correcte resultaat geldt alleen voor deze situatie en deze SUT. De test faalt als het correcte resultaat niet gelijk is aan het daadwerkelijke resultaat. Je kunt bewijzen dat een SUT correct werkt door dit meerdere keren te doen voor dezelfde SUt in verschillende situaties. Voorbeelden zijn veruit de meest gebruikte aanpak voor het definiëren van correct. Om een test te schrijven met dit type correct doen we het volgende:
- Maak een voorbeeld state
- Voer de Subject Under Test uit met voorbeeld input
- Assert of het daadwerkelijke resultaat hetzelfde is als het correcte resultaat
Deze stappen zou je kunnen herkennen als het AAA-patroon (Arrange, Act, Assert). Correct is gedefinieerd als een of meer assertions in de derde stap. Deze definitie geldt alleen voor dit voorbeeld, een ander voorbeeld heeft een andere definitie van correct en dus ook andere assertions.
Regel
Een regel is een herbruikbare bundel van logica, vaak met een mooie naam. Een regel wordt overtreden wanneer de input niet correct is volgens de logica van de regel. Een regel mag nooit gebroken worden, onafhankelijk van de state, input, of Subject Under Test (SUT). Een gebroken regel faalt de test. Je kunt bewijzen dat de SUT correct werkt door met meerdere regels te testen.
Omdat een regel nooit gebroken mag worden, zal een regel zichzelf soms uitzetten. Bijvoorbeeld, wanneer de regel niet relevant is bij de input. Zichzelf uitzetten zou onacceptabel zijn bij voorbeelden, maar is prima bij regels. Om een test te schrijven met dit type correct doen we het volgende:
- Schrijf een regel
- Voer de regel uit met een voorbeeld situatie (= state en input) en de Subject Under Test
- Assert of de regel is gebroken
Een voordeel van regels is herbruikbaarheid. Hierdoor kunnen we stap twee meerdere keren uitvoeren met gegeneerde input (e.g. Property-based testing). Het stelt ons ook in staat om regelsets te maken die we kunnen delen tussen applicaties en teams (e.g. Linters).
Correct op meerder manieren gebruiken
Met de fundamentele aanpakken van correct kunnen we andere testaanpakken beter begrijpen. Ik ben nog geen testaanpak tegengekomen die niet gedefinieerd kan worden als voorbeelden en/of regels.
De meeste niet-fundamentele aanpakken combineren correct met andere aspecten van software development. Bijvoorbeeld, Contract-based testing definieert correct met regels afgeleid van contracten. Daarnaast biedt het een gestructureerde manier voor teams om samen te werken en dezelfde taal te spreken.
Andere aanpakken combineren beide fundamentele aanpakken om tot een betere definitie van correct te komen. Bijvoorbeeld, Property-based testing definieert correct door een voorbeeld in een regel te verpakken. Het resultaat is vele regel-gegenereerde voorbeelden die samen een solide definitie van correct opleveren.
Er zijn nog veel meer aanpakken te verkennen. Ik ben bezig met een overzicht van testaanpakken waarbij regels en voorbeelden centraal staan. Dit zal helaas moeten wachten tot een volgend artikel.
Conclusie
Om te bewijzen dat onze software goed werkt, moeten we eerst definiëren wat correct is. Correct wordt gedefinieerd op basis van requirements, ervaring en vaardigheden. Soms definiëren we correct impliciet, maar het is beter als we het expliciet maken.
We kunnen correct definiëren op twee manieren: voorbeelden en regels. Voorbeelden vereisen een specifieke situatie en correct resultaat voor een Subject Under Test. Regels zijn herbruikbaar en mogen niet overtreden worden, onafhankelijk van de situatie of Subject Under Test. We kunnen veel interessante testaanpakken definiëren in termen van voorbeelden en regels. In een volgend artikel besteed ik hier graag aandacht aan.