Hvad er mutationstest? (Eksempel)
⚡ Smart opsummering
Mutationstestning introducerer bevidst små fejl i kildekoden og kører derefter den eksisterende testsuite mod hver fejlbehæftet version for at måle, om disse tests er stærke nok til at registrere ændringen.

Hvad er mutationstestning?
Mutationstest er en type softwaretest, hvor bestemte udsagn i kildekoden ændres eller muteres for at kontrollere, om testcasene er i stand til at finde fejl i kildekoden. Målet med mutationstestning er at sikre testcasenes kvalitet med hensyn til robusthed, så de fejler mod den muterede kildekode.
Ændringen i et mutantprogram skal holdes ekstremt lille, så den ikke påvirker programmets overordnede mål. Mutationstestning kaldes også en fejlbaseret teststrategi, fordi den involverer bevidst at skabe en fejl i programmet. Det er en form for Hvid Box Test som primært anvendes under Enhedstest.
Mutationstestning blev foreslået i 1971 i en studenterartikel af Richard Lipton og formaliseret i artiklen "Hints on Test Data Selection" fra 1978 af DeMillo, Lipton og Sayward. Den mistede momentum på grund af datidens computeromkostninger og har siden genvundet terræn for sprog som Java, C#, Python, JavaScript og XML.
Hvordan udfører man mutationstest?
Følgende er trinnene til at udføre mutationstestning, også kendt som mutationsanalyse:
Trin 1: Fejl introduceres i programmets kildekode ved at oprette mange versioner kaldet mutanter. Hver mutant skal indeholde en enkelt fejl, og målet er at få mutantversionen til at fejle, hvilket demonstrerer testtilfældenes effektivitet.
Trin 2: Testtilfælde anvendes på det oprindelige program og også på mutantprogrammet. Test sag bør være tilstrækkelig, og den er tilpasset til at opdage fejl i et program.
Trin 3: Sammenlign resultaterne af det oprindelige og mutantprogrammet.
Trin 4: Hvis det originale program og mutantprogrammet genererer forskelligt output, dræbes mutanten af testcasen. Derfor er testcasen god nok til at detektere ændringen mellem det originale program og mutantprogrammet.
Trin 5: Hvis det originale program og mutantprogrammet genererer det samme output, holdes mutanten i live. I sådanne tilfælde skal der oprettes mere effektive testtilfælde, der dræber alle mutanterne.
Diagrammet nedenfor tracer de samme fem trin, fra det oprindelige program gennem mutantgenerering til den dræbte eller overlevende dom.
Hvordan opretter man mutantprogrammer?
En mutation er intet andet end en enkelt syntaktisk ændring, der foretages i en programsætning. Hvert mutantprogram skal afvige fra det oprindelige program med præcis én mutation.
| Originalt program | Mutant program |
| Hvis (x>y) Udskriv "Hej" Else Udskriv "Hej" |
Hvis (x Udskriv "Hej" Else Udskriv "Hej" |
I parret ovenfor er kun sammenligningsoperatoren ændret, men et testtilfælde, hvor x er større end y, udskriver nu "Hej" i stedet for "Hej". Illustrationen viser den ene syntaktiske redigering.
Hvad skal man ændre i et mutantprogram?
Der findes adskillige teknikker, der kan bruges til at generere mutantprogrammer. De tre familier nedenfor dækker de fleste af de mutationsoperatorer, som værktøjer leveres med.
| Operaog erstatningsoperatører | Udtryksmodifikationsoperatorer | Operatorer for ændring af erklæringer |
| Erstat operanden med en anden operand (x med y, eller y med x) eller med en konstant værdi. | Erstat en operator, eller indsæt en ny operator, i en programsætning. | Programmatiske udsagn modificeres for at skabe mutantprogrammer. |
| Eksempel: If(x>y) erstatte x- og y-værdier If(5>y) erstatte x med konstant 5 |
Eksempel: Hvis(x==y) Vi kan erstatte == med >= og få mutantprogrammet som If(x>=y) og indsætte ++ i sætningen Hvis(x==++y) |
Eksempel: Slet den anden del i en if-else-sætning Slet hele if-else-sætningen for at kontrollere, hvordan programmet opfører sig |
Nogle eksempler på mutationsoperatorer:
- GOTO etiket udskiftning
- Udskiftning af returerklæring
- Sletning af erklæring
- Indsættelse af unær operator (såsom – og ++)
- Udskiftning af logisk stik
- Sammenlignelig udskiftning af arraynavn
- Fjernelse af else-delen af en if-else-sætning
- Tilføjelse eller udskiftning af operatorer
- Erstatning af erklæring ved at ændre dataene
- Dataændring for variablerne
- Ændring af datatyper i programmet
OperaTorer, der berører en randbetingelse, overlever oftest, så mutationsresultater peger ofte tilbage på huller i grænseværdianalyse.
Typer af mutationstestning
In Software EngineeringMutationstestning er grundlæggende kategoriseret i tre typer - udsagnsmutation, værdimutation og beslutningsmutation.
- Statement Mutation – en sætning klippes, indsættes eller slettes, så resultatet kan være, at nogle linjer kode fjernes.
- Værdimutation – værdierne af primære parametre og konstanter ændres, for eksempel ændring af en løkkegrænse eller en tærskel.
- Beslutningsmutation – kontrolsætninger ændres, for eksempel flipping en relationel operator eller negation af en betingelse.
Værktøjer grupperer deres operatorer under disse tre overskrifter, så familien, der producerede en overlevende mutant, fortæller testeren, hvilken type påstand der mangler. En overlevende beslutningsmutant markerer normalt en utestet gren, som overlapper med looptestning.
Automatisering af mutationstestning
Mutationstestning er ekstremt tidskrævende og kompliceret at udføre manuelt, så det anbefales at bruge automatiseringsværktøjer, som også reducerer omkostningerne. Et mutationsværktøj samler mutanterne, planlægger kørslerne, registrerer hvilken mutant hver enkelt fejlende test dræbte, og rapporterer scoren.
Liste over tilgængelige værktøjer:
- Stryker — et open source-rammeværk til mutationstestning med udgaver til JavaManuskript og TypeScript (StrykerJS), C# og .NET (Stryker.NET) og Scala (Stryker4s).
- PIT, også skrevet PITest — et mutationstestsystem til Java og JVM'en, der muterer den kompilerede bytekode og tilsluttes Maven og Gradle bygger ved siden af JUnit.
Begge kører som et byggetrin, så de hører hjemme i det samme kontinuerlig integration rørledningen som resten af automatiseringstest på.
Mutationsscore
Mutationsscoren er defineret som procentdelen af dræbte mutanter ud af det samlede antal mutanter.
Mutationsscore = (dræbte mutanter/samlet antal mutanter) * 100
Formlen er vist nedenfor i den form, som de fleste værktøjer rapporterer den.
Testtilfælde beskrives som mutationsfyldestgørende, når scoren når 100 procent. I praksis skal nævneren udelukke ækvivalente mutanter — mutanter hvis ændrede syntaks opfører sig præcis som originalen, så ingen test kan dræbe dem. Værktøjer rapporterer derfor dræbte mutanter divideret med dræbte plus overlevende ikke-ækvivalente mutanter og lader testeren markere ækvivalenter.
Eksperimentelle resultater har vist, at mutationstestning er en effektiv måde at måle tilstrækkeligheden af testcases. Den største ulempe er omkostningerne ved at generere mutanterne og udføre hver testcase mod hver enkelt.
Mutationstest vs. Code Dækning
Høj test dækning beviser ikke stærke tests. Linje- og branch coverage registrerer hvilke udsagn der blev kørt, ikke om noget blev verificeret bagefter, så en test, der kalder en metode og ikke hævder noget, tæller stadig som dækket. Mutationstest lukker dette hul, fordi en mutant kun dør, når en assertion rent faktisk fejler.
| Aspect | Code dækning | Mutationsscore |
| Hvad det måler | Hvilke linjer eller grene testene blev udført | Hvilke injicerede fejl testene detekterede |
| Følsom over for påstande | Nej — en test med nul påstande tilføjer stadig dækning | Ja — en mutant overlever, når ingen påstand fejler |
| Prisen for en løbetur | Én instrumenteret testkørsel | Én testkørsel pr. overlevende mutant, indtil videre langsommere |
| Typisk brug | En hurtig gate på hver commit | En grundigere periodisk kontrol af kritiske moduler |
| Fejl tilstand | 100 procent dækning uden reel verifikation | Ækvivalente mutanter, der aldrig kan dræbes |
De to målinger komplementerer hinanden. Dækningsgraden angiver den kode, der aldrig blev nået; mutationsscoren angiver den nåede kode, der aldrig blev kontrolleret. Begge giver den samme information. proces til håndtering af fejl, sammen med foranstaltninger som f.eks. defektdensitet.
Fordele ved mutationstestning
Følgende er fordelene ved mutationstest:
- Det er en effektiv metode til at opnå høj dækning af kildeprogrammet.
- Den tester selve testsuiten, som ingen andre softwaretestteknik gør direkte.
- Mutationstestning giver softwareudvikleren et godt niveau af fejldetektion.
- Metoden afdækker tvetydigheder i kildekoden og har kapacitet til at afsløre fejl, som almindelige kørsler aldrig når.
- Overlevende mutanter kan gribes an: hver enkelt navngiver en specifik linje og en specifik ændring, som suiten ikke bemærkede.
- Kunderne drager fordel af denne testning ved at modtage et mere pålideligt og stabilt system.
Ulemper ved mutationstestning
På den anden side er der følgende ulemper ved mutationstestning:
- Mutationstestning er ekstremt dyrt og tidskrævende, fordi et stort antal mutantprogrammer skal genereres og kompileres.
- Da det er tidskrævende, er det rimeligt at sige, at denne testning ikke kan udføres uden et automatiseringsværktøj.
- Hver mutant udføres med det samme antal testcases som det oprindelige program, så en stor mutantpopulation skal køres mod hele testsuiten.
- Tilsvarende mutanter kan ikke dræbes af nogen test, og adskillelse af dem fra ægte overlevende kræver normalt manuel gennemgang.
- Da metoden ændrer kildekoden, er den ikke anvendelig på Sort Box Test.
Hvornår skal man bruge mutationstestning
Ovenstående omkostningsprofil betyder, at mutationstestning sjældent køres på tværs af en hel kodebase ved hver commit. Det betaler sig selv, hvor en uopdaget fejl er dyr, og den kode, der testes, er lille nok til at mutere hurtigt.
- Sikkerhedskritisk eller økonomisk logik — betalingsberegning, skatteregler og godkendelsestjek, hvor et tavst forkert svar er værre end et nedbrud.
- Suiter med mistænkeligt høj dækning — når dækningen er tæt på 100 procent, men der stadig undslipper fejl.
- Ældre kode refaktoreres — mutationsresultater afslører, om de eksisterende tests ville fange en regression.
- Biblioteker og delte komponenter — en fejl i en genbrugt komponent multipliceres på tværs af hver opkalder.
- Hold der øver testdrevet udvikling — scoren kontrollerer, at de først skrevet prøver udfører et rigtigt arbejde.
Det er normalt ikke værd at køre på engangsprototyper, på tynd lim eller genereret kode uden forgreningslogik, eller på pakker domineret af langsomme integrationstests som allerede tager timer for en enkelt gennemkørsel.
De fleste teams dækker derfor kørslen til ændrede filer, sætter en tærskel for de moduler, der er vigtige, og lader den bredere regressionstest suiten bærer resten af livscyklus for softwaretest.



