Wat is mutatietesten? (Voorbeeld)
⚡ Slimme samenvatting
Mutatietesten introduceren opzettelijk kleine fouten in de broncode en voeren vervolgens de bestaande testsuite uit op elke foutieve versie, waarbij wordt gemeten of die tests sterk genoeg zijn om de wijziging te detecteren.
Wat is mutatietesten?
Mutatie testen Mutatietesten is een vorm van softwaretesten waarbij bepaalde onderdelen van de broncode worden gewijzigd, of gemuteerd, om te controleren of de testgevallen fouten in de broncode kunnen vinden. Het doel van mutatietesten is om de robuustheid van de testgevallen te waarborgen, zodat ze falen bij de gemuteerde broncode.
De wijziging die in een gemuteerd programma wordt aangebracht, moet extreem klein zijn, zodat deze het algemene doel van het programma niet beïnvloedt. Mutatietesten wordt ook wel een foutgebaseerde teststrategie genoemd, omdat er opzettelijk een fout in het programma wordt gecreëerd. Het is een vorm van Wit Box Testen dat voornamelijk wordt toegepast tijdens Testen van een eenheid.
Mutatietesten werden in 1971 voorgesteld in een studentenpaper van Richard Lipton en geformaliseerd in het artikel "Hints on Test Data Selection" uit 1978 van DeMillo, Lipton en Sayward. Het verloor aan populariteit vanwege de hoge rekenkosten van die tijd, maar heeft sindsdien weer terrein gewonnen voor talen zoals Java, C#, Python, JavaScript en XML.
Hoe voer je een Mutatietest uit?
Hieronder volgen de stappen voor het uitvoeren van mutatietesten, ook wel mutatieanalyse genoemd:
Stap 1: Fouten worden in de broncode van het programma geïntroduceerd door vele versies te creëren, mutanten genaamd. Elke mutant moet één fout bevatten, en het doel is om de mutantversie te laten falen, wat de effectiviteit van de testgevallen aantoont.
Stap 2: Testgevallen worden toegepast op het oorspronkelijke programma en ook op het gemuteerde programma. Testgeval zou voldoende moeten zijn, en het is aangepast om fouten in een programma te detecteren.
Stap 3: Vergelijk de resultaten van het oorspronkelijke en het gemuteerde programma.
Stap 4: Als het oorspronkelijke programma en het gemuteerde programma een verschillende uitvoer genereren, wordt het gemuteerde programma door de testcase uitgeschakeld. De testcase is dus voldoende om de verschillen tussen het oorspronkelijke en het gemuteerde programma te detecteren.
Stap 5: Als het oorspronkelijke programma en het gemuteerde programma dezelfde uitvoer genereren, blijft de mutant bestaan. In dergelijke gevallen moeten effectievere testgevallen worden ontwikkeld die alle mutanten uitschakelen.
Het onderstaande diagram tracHet doorloopt dezelfde vijf stappen, van het oorspronkelijke programma via de generatie van mutanten tot het oordeel of de mutant gedood of overleefd is.
Hoe Mutant-programma's maken?
Een mutatie is niets anders dan een enkele syntactische wijziging die wordt aangebracht in een programmaregel. Elk gemuteerd programma moet precies één mutatie verschillen van het originele programma.
| Origineel programma | Mutantenprogramma |
| Als (x>y) Afdrukken “Hallo” Anders Druk “Hallo” af |
Als (x Afdrukken “Hallo” Anders Druk “Hallo” af |
In het bovenstaande paar is alleen de vergelijkingsoperator veranderd, maar een testgeval waarbij x groter is dan y print nu "Hi" in plaats van "Hello". De illustratie laat die ene syntactische aanpassing zien.
Wat moet er veranderd worden in een Mutant Programma?
Er zijn verschillende technieken die gebruikt kunnen worden om gemuteerde programma's te genereren. De drie onderstaande categorieën omvatten de meeste mutatieoperatoren die standaard in de tools aanwezig zijn.
| Operand vervangende operatoren | Operators voor het wijzigen van expressies | Operators voor het wijzigen van verklaringen |
| Vervang de operand door een andere operand (x door y, of y door x) of door een constante waarde. | Vervang een operator in een programmaregel of voeg een nieuwe operator in. | Programmatische instructies worden aangepast om mutante programma's te maken. |
| Voorbeeld: If(x>y) vervang x- en y-waarden Als(5>y) vervang x door constante 5 |
Voorbeeld: Als(x==y) We kunnen == vervangen door >= en het gemuteerde programma als volgt verkrijgen: If(x>=y) en het invoegen van ++ in de instructie Als(x==++y) |
Voorbeeld: Verwijder het else-gedeelte in een if-else-instructie Verwijder de volledige if-else-instructie om te controleren hoe het programma zich gedraagt. |
Enkele voorbeelden van mutatieoperatoren:
- GOTO-labelvervanging
- Vervanging retourverklaring
- Verklaring verwijderen
- Invoeging van unaire operatoren (zoals – en ++)
- Vervanging van logische connectoren
- Vergelijkbare vervanging van de arraynaam
- Het verwijderen van het 'else'-gedeelte van een if-else-instructie
- Operators toevoegen of vervangen
- Vervanging van verklaringen door de gegevens te wijzigen
- Gegevensaanpassing voor de variabelen
- Wijziging van gegevenstypen in het programma
OperaTors die een randvoorwaarde raken, overleven het vaakst, dus mutatieresultaten wijzen vaak terug op hiaten in grenswaarde analyse.
Soorten mutatietesten
In Software EngineeringMutatietesten worden in principe onderverdeeld in drie typen: statementmutatie, waardemutatie en beslissingsmutatie.
- Verklaring Mutatie – een instructie wordt geknipt, geplakt of verwijderd, waardoor mogelijk enkele regels code worden verwijderd.
- Waardemutatie – De waarden van primaire parameters en constanten worden gewijzigd, bijvoorbeeld door een lusgrens of een drempelwaarde aan te passen.
- Beslissingsmutatie – besturingsinstructies worden gewijzigd, bijvoorbeeld flippenping een relationele operator of het ontkennen van een voorwaarde.
De tools groeperen hun operators onder deze drie rubrieken, zodat de familie die een overlevende mutant heeft geproduceerd de tester vertelt welk type bewering ontbreekt. Een overlevende beslissingsmutant markeert meestal een ongeteste tak, die overlapt met lus testen.
Automatisering van mutatietests
Mutatietesten zijn extreem tijdrovend en complex om handmatig uit te voeren. Daarom is het raadzaam om automatiseringstools te gebruiken, wat ook de kosten verlaagt. Een mutatietool compileert de mutanten, plant de uitvoeringen in, registreert welke mutant bij elke mislukte test wordt verwijderd en rapporteert de score.
Lijst met beschikbare tools:
- Stryker — een open-source framework voor mutatietesten met edities voor JavaScriptie en TypeScript (StrykerJS), C# en .NET (Stryker.NET), en Scala (Stryker4s).
- PIT, ook wel geschreven als PITest — een mutatietestsysteem voor Java en de JVM die gecompileerde bytecode muteert en aansluit op Maven en Gradle bouwt ernaast JUnit.
Beide worden uitgevoerd als een build-stap, dus ze horen in hetzelfde pakket thuis. continue integratie pijpleiding, net als de rest van de automatisering testen op.
Mutatiescore
De mutatiescore wordt gedefinieerd als het percentage gedode mutanten ten opzichte van het totale aantal mutanten.
Mutatiescore = (Gedode Mutanten / Totaal aantal Mutanten) * 100
De formule wordt hieronder weergegeven in de vorm zoals de meeste tools deze presenteren.
Testgevallen worden als mutatie-adequaat beschouwd wanneer de score 100 procent bereikt. In de praktijk moet de noemer het volgende uitsluiten: equivalente mutanten — mutanten waarvan de gewijzigde syntaxis zich exact hetzelfde gedraagt als het origineel, waardoor geen enkele test ze kan uitschakelen. Tools rapporteren daarom het aantal uitgeschakelde mutanten gedeeld door het aantal uitgeschakelde plus het aantal overgebleven niet-equivalente mutanten, en laten de tester de equivalenten markeren.
Experimentele resultaten hebben aangetoond dat mutatietesten een effectieve manier zijn om de geschiktheid van testgevallen te meten. Het belangrijkste nadeel is de kosten van het genereren van de mutanten en het uitvoeren van elk testgeval tegen elke mutant.
Mutatietesten versus Code Dekking
Hoge test dekking Dit bewijst niet dat de tests sterk zijn. Regel- en vertakkingsdekking registreert welke instructies zijn uitgevoerd, niet of er daarna iets is geverifieerd. Een test die een methode aanroept en niets controleert, telt dus nog steeds als gedekt. Mutatietesten dichten die kloof, omdat een mutant alleen sterft wanneer een bewering daadwerkelijk mislukt.
| Aspect | Code dekking | Mutatiescore |
| Wat het meet | Welke regels of vertakkingen werden er getest? | Welke fouten werden er geïnjecteerd tijdens de tests? |
| Gevoelig voor beweringen | Nee, een test zonder beweringen voegt nog steeds dekking toe. | Ja, een mutant overleeft wanneer geen enkele bewering faalt. |
| Kosten van een run | Eén instrumentele testrun | Eén testrun per overlevende mutant, tot nu toe veel langzamer. |
| Typisch gebruik | Een snelle controle bij elke commit. | Een grondigere periodieke controle van kritieke modules |
| Faal modus | 100 procent dekking zonder echte verificatie | Gelijkwaardige mutanten die nooit gedood kunnen worden |
De twee meetwaarden vullen elkaar aan. De code coverage geeft aan welke code nooit is bereikt; de mutatiescore geeft aan welke code wel is bereikt, maar nooit is gecontroleerd. Beide leveren dezelfde resultaten op. defectbeheerproces, naast maatregelen zoals defectdichtheid.
Voordelen van mutatietesten
Hieronder volgen de voordelen van mutatietesten:
- Het is een krachtige methode om een hoge dekking van het bronprogramma te bereiken.
- Het test de testsuite zelf, wat geen andere software testtechniek doet dat direct.
- Mutatietesten bieden softwareontwikkelaars een goede mate van foutdetectie.
- De methode legt onduidelijkheden in de broncode bloot en kan fouten aan het licht brengen die bij normale uitvoeringen nooit worden ontdekt.
- De overgebleven mutanten zijn aanspreekbaar: elk van hen noemt een specifieke regel en een specifieke wijziging die de software niet heeft opgemerkt.
- Klanten profiteren van deze tests doordat ze een betrouwbaarder en stabieler systeem ontvangen.
Nadelen van mutatietesten
Aan de andere kant zijn de volgende nadelen verbonden aan mutatietesten:
- Mutatietesten zijn extreem kostbaar en tijdrovend, omdat er een groot aantal gemuteerde programma's gegenereerd en gecompileerd moet worden.
- Omdat het tijdrovend is, kun je gerust stellen dat deze test niet zonder een automatiseringstool kan worden uitgevoerd.
- Elke mutant wordt getest met hetzelfde aantal testgevallen als het oorspronkelijke programma, dus een grote populatie mutanten moet worden getest met de volledige testsuite.
- Gelijkwaardige mutanten kunnen door geen enkele test worden gedood, en het onderscheiden ervan van echte overlevenden vereist meestal handmatige beoordeling.
- Omdat de methode de broncode wijzigt, is deze niet toepasbaar op Zwart Box Testen.
Wanneer moet je mutatietesten gebruiken?
Het bovenstaande kostenprofiel betekent dat mutatietesten zelden bij elke commit op de volledige codebase worden uitgevoerd. Het betaalt zichzelf terug wanneer een onopgemerkte fout kostbaar is en de te testen code klein genoeg is om snel te muteren.
- Veiligheidskritische of financiële logica — betalingsberekening, belastingregels en autorisatiecontroles, waarbij een stilzwijgend fout antwoord erger is dan een ongeluk.
- Suites met verdacht hoge dekking — wanneer de dekking bijna 100 procent bedraagt, maar er toch nog defecten door de mazen van het net glippen.
- Verouderde code wordt herzien. — De resultaten van de mutatietests laten zien of de bestaande tests een regressie zouden detecteren.
- Bibliotheken en gedeelde componenten — een fout in een hergebruikt bestanddeel vermenigvuldigd met elke beller.
- Teams die oefenen test gedreven ontwikkeling — De score controleert of de eerst afgenomen tests daadwerkelijk effectief zijn.
Het is meestal niet de moeite waard om te werken met wegwerpprototypes, met dunne verbindingsstukken of gegenereerde code zonder vertakkingslogica, of met testsuites die gedomineerd worden door trage code. integratietests die nu al uren in beslag nemen voor één enkele doorgang.
De meeste teams beperken de run daarom tot gewijzigde bestanden, stellen een drempelwaarde in voor de modules die ertoe doen, en laten de rest over aan de rest. regressietesten suite draagt de rest van de levenscyclus van softwaretests.



