Mutatsioonitestimine

Mutatsioonitestimine on üks testimise vorme, mille abil saab luua uusi tarkvarateste või hinnata olemasolevate testide kvaliteeti. Mutatsioonitestimine kaasab programmi lähtekoodi muutmist väikeste osade kaupa. 
Igat muudetud programmiosa nimetatakse mutandiks"," mille toimel võib modifitseeritud programmi käitumine erineda esialgsest programmist"." Mutandid põhinevad rangelt defineeritud mutatsioonioperaatorite põhjal, mis imiteerivad tüüpilisi programmeerimisvigu (näiteks kasutades väärasid aritmeetilisi operaatoreid) ning mille toimel avastatakse programmis veaohtlikke koodijuppe. Selliste muutuste avastamist olemasolevate testide poolt nimetatakse mutandi tapmiseks"." Programmi testikomplekte saab hinnata selle põhjal, kui suure osa mutantidest antud testid ära tapavad. Selle kaudu saab luua uusi teste, et tappa mutante, mida algne testikomplekt ei avastanud. Mutatsioonitestimine on osa valge kasti meetodi tüüpidest.
Ajalugu.
Esialgse mutatsioonitestimisese idee pakkus välja Richard Lipton aastal 1971. Teooriat arendas ja selle avaldas Lipton koos Richard DeMillo ja Fred Saywardiga aastal 1978. Esimese mutatsioonitestimisetööriista lõi Timothy Budd aastal 1980 Yale'i ülikoolis.
Ülevaade.
Mutatsioonitestimisel on mitu eesmärki:
Mutatsioonitestimine põhineb kahel hüpoteesil. Esimene hüpotees on pädeva programmeerija hüpotees, mille kohaselt suurem osa kogenud programmeerija tarkvaras esinevatest vigastest tuleneb väiksematest süntaksivigadest. Teiseks hüpoteesiks on sidestamise mõju"," mille kohaselt võib väiksemate vigade toimel koodis avalduda suuremad, seni teadmata vead.
Vähemärgatavatele vigadele saavad tähelepanu juhtida kõrgema järgu mutandid, mis toetavad samuti sidestamise mõju. Kõrgema järgu mutante saab kasutusele võtta luues mutante, millel on rohkem kui üks mutatsioon.
Mutatsioonitestimist sooritatakse lähtekoodi peal, võttes aluseks hulga mutatsioonioperaatoreid ning rakendades neid iga sobiva koodijupi peal.
Näiteks olgu programmil järgnev koodijupp:
if (a &amp;&amp; b) {
 c = 1;
} else {
 c = 0;
Antud koodijupi peal rakendatakse tingimuslikku mutatsioonioperaatorit, mille toimel asendatakse konjunktsioon codice_1 disjunktsiooniga codice_2. Tulemuseks tekib järgnev mutant:
if (a || b) {
 c = 1;
} else {
 c = 0;
Programmi testikomplekt peaks antud mutandi tapmiseks täitma kolm tingimust:
Antud tingimused moodustavad RIP ("Repeat-Induced Point)" mudeli. Kasutades RIP-mudelit, saame eristada kahte mutatsioonitestimisliiki. Nõrgaks mutatsioonitestimiseks nimetatakse testimist, mis rahuldab RIP-mudeli esimesed kaks tingimust. Tugevaks mutatsioonitestimiseks nimetatakse testimist, mis rahuldab kõik kolm RIP-mudeli tingimust.
Ekvivalentsed mutandid.
Teatud mutantide korral ei ole võimalik luua sellist testikomplekti, mis suudaks antud mutandi ära tappa, kuna muteerunud programm oleks iga vaheseisundi korral sama käitumisega kui algne programm. Selliseid mutante nimetatakse ekvivalentseteks mutantideks.
Näiteks olgu antud järgmine koodijupp:
i = 0
while (true) {
 i++
 if (i == 5) break;
Ekvivalentne mutant tekiks näiteks siis, kui asendaksime operaatori codice_6 operaatoriga codice_7 . Tulemuseks oleks kood kujul:
i = 0
while (true) {
 i++
 if (i &gt;= 5) break;
Hoolimata sellest, et on muudetud tsükli lõpptingimuse kontrolli, lõpetab siiski programm töö alati samal juhul, kui esialgne programm. Seetõttu on mutant eristamatu algprogrammist. Ekvivalentsete mutantide leidmine, isegi väiksemate programmide puhul, on tihti ajakulukas erinevate seisundite ülevaatamise tõttu.