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.[1]

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.[2]

Ajalugu muuda

Esialgse mutatsioonitestimisese idee pakkus välja Richard Lipton aastal 1971.[3] Teooriat arendas ja selle avaldas Lipton koos Richard DeMillo ja Fred Saywardiga aastal 1978.[1] Esimese mutatsioonitestimisetööriista lõi Timothy Budd aastal 1980 Yale'i ülikoolis.[3]

Ülevaade muuda

Mutatsioonitestimisel on mitu eesmärki:

  • tuvastada sellised koodiosad, mille korral mutante ära ei tapeta;[1]
  • tuvastada ebaefektiivsed ning ebavajalikud testid, mis ei tapa ühtegi mutanti;[4]
  • arvutada välja programmi testikomplekti headus tapetud mutantide ja mutantide koguarvu suhtena;[5]
  • uurida programmi vigade levikut mutantide lisamisel.[6]

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.[1] Teiseks hüpoteesiks on sidestamise mõju, mille kohaselt võib väiksemate vigade toimel koodis avalduda suuremad, seni teadmata vead.[7][8]

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.[7]

Mutatsioonitestimist sooritatakse lähtekoodi peal, võttes aluseks hulga mutatsioonioperaatoreid ning rakendades neid iga sobiva koodijupi peal.[5]

Näiteks olgu programmil järgnev koodijupp:

if (a && b) {
    c = 1;
} else {
    c = 0;
}

Antud koodijupi peal rakendatakse tingimuslikku mutatsioonioperaatorit, mille toimel asendatakse konjunktsioon && disjunktsiooniga ||. Tulemuseks tekib järgnev mutant:

if (a || b) {
    c = 1;
} else {
    c = 0;
}

Programmi testikomplekt peaks antud mutandi tapmiseks täitma kolm tingimust:

  1. test peab jõudma muteerunud lauseni;
  2. testi sisendandmed peavad olema sellised, et algprogrammi ja muteerunud programmi vaheseisundid oleksid erinevad. Antud testi puhul sobivad sellisteks sisendandmeteks väärtused a = 1 ja b = 0;
  3. algprogrammist erinev vaheseisund (muutuja c väärtus) peab kajastuma programmi väljundis ning olema testi poolt kontrollitud.[3]

Antud tingimused moodustavad RIP (Repeat-Induced Point) mudeli[3]. 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.[2]

Ekvivalentsed mutandid muuda

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.[9]

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 == operaatoriga >= . Tulemuseks oleks kood kujul:

i = 0
while (true) {
    i++
    if (i >= 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.[9]

Viited muuda

  1. 1,0 1,1 1,2 1,3 Richard A. DeMillo, Richard J. Lipton, Fred G. Sayward. (1978). Hints on test data selection: Help for the practicing programmer. IEEE Computer.{{raamatuviide}}: CS1 hooldus: mitu nime: autorite loend (link)
  2. 2,0 2,1 A. Jefferson Offutt, Roland H. Untch. "Mutation 2000: Uniting the Orthogonal" (PDF). Originaali (PDF) arhiivikoopia seisuga 2016-04-12. Vaadatud 20. okt. 2018. {{netiviide}}: kontrolli kuupäeva väärtust: |Kasutatud= (juhend)
  3. 3,0 3,1 3,2 3,3 A. Jefferson Offutt, Roland H. Untch. "Mutation 2000: Uniting the Orthogonal" (PDF). Originaali (PDF) arhiivikoopia seisuga 2016-04-12. Vaadatud 20. okt. 2018. {{netiviide}}: kontrolli kuupäeva väärtust: |Kasutatud= (juhend)
  4. Smith B. (2008). On Guiding Augmentation of an Automated Test Suite via Mutation Analysis.
  5. 5,0 5,1 Paul Ammann,Jeff Offutt (2008). Introduction to Software Testing. Cambridge University Press.
  6. Musco, Vincenzo; Monperrus, Martin; Preux, Philippe (2016). "Mutation-Based Graph Inference for Fault Localization". Vaadatud 20. okt. 2018. {{netiviide}}: kontrolli kuupäeva väärtust: |Kasutatud= (juhend)CS1 hooldus: mitu nime: autorite loend (link)
  7. 7,0 7,1 A. Jefferson Offutt (1992). Investigations of the software testing coupling effect. Lk 5–20.
  8. A. T. Acree, T. A. Budd, R. A. DeMillo, R. J. Lipton, F. G. Sayward (1979). Mutation Analysis. Georgia Institute of Technology, Atlanta, Georgia osariik.{{raamatuviide}}: CS1 hooldus: mitu nime: autorite loend (link)
  9. 9,0 9,1 P. G. Frankl, S. N. Weiss, C. Hu. (1997). All-uses versus mutation testing: An experimental comparison of effectiveness (38. trükk). Lk 235–253.{{raamatuviide}}: CS1 hooldus: mitu nime: autorite loend (link)