Aféierung fir Mutatiounstest

Mutatioun Testen (op Franséisch: tests de mutation), Ech hunn viru kuerzem dëse Begrëff entdeckt, deen e Prozess beschreift, dee fäeg ass Lücken an Eenheetstester z'entdecken, iwwer d'Codedeckung erausgoen. Haut presentéieren ech Iech dës Approche, déi aus der Ausféierung vun dësen Tester besteet andeems Dir de Code handelt.

Eenheet Tester

Bedenkt datt d'Nëtzlechkeet vun Eenheetstest gutt etabléiert ass, gëtt dëst Thema interessant wann Dir e getestene Projet entwéckelt, egal wéi wichteg de Codeofdeckung.
D'Eenheetstester erlaben d'Highlight vu méigleche Regressiounen, déi duerch eng Ännerung vum Code verursaacht ginn. An der Theorie, wann d'Tester de Programm validéieren, heescht et datt alles richteg an der Applikatioun funktionnéiert. Als éischt an dacks déi eenzeg Moossnam vu Vertrauen benotze mir Code Cover. Wat dës Metrik méi no bei 100% kënnt, wat et eis méi berouegt datt keng Regressioun duerch d'Risse rutscht. Leider bleift dës Behaaptung theoretesch.
D'Tester, obwuel essentiell fir d'Validatioun vun enger qualitativer Applikatioun, et ass schwéier hir Relevanz ze demonstréieren oder souguer ze schätzen.

Code Ofdeckung a Fall Ofdeckung

100% Code Ofdeckung heescht net 100% validéiert Code awer nëmmen 100% vun dësem Code ausgefouert wann d'Tester Passë, näischt méi.
Code Ofdeckung (Linn, Ausso, Branche, etc.) Moossnamen nëmme wat Code duerch d'Tester ausgefouert gouf, ouni Garantie fir Detektioun vu Mängel. Et ass nëmmen fäeg de Code z'identifizéieren deen nach net getest ass.
Testen ouni Behaaptung ass dat offensichtlech Beispill well, obwuel ausgefouert gëtt, gëtt de Code net tatsächlech getest. Glécklecherweis bleift dëst Szenario rar, am meeschte verbreet ass de Code ze begéinen deen deelweis vun der Testsuite getest gëtt. Eng Suite déi nëmmen deelweis Code test deen nach ëmmer all seng Filialen ausféiere kann.
An e puer Fäll ass Code Ofdeckung net en Indikator vum Schutz. Hei ass en einfacht Beispill:

function isAdult(user) {
    return user.age >= 18;
}

Ugeholl mir wëllen den Alter vun engem Benotzer kontrolléieren. Mir schreiwen de folgende Code fir sécherzestellen datt et grouss ass.
Fir dëse Code ze testen kënne mir probéieren mat 12 an 38 als Input. Dës Aktioun wier genuch fir dëse Code 100% ze decken.
D'Resultat wier d'selwecht wa mir ausgoen 18 als Majoritéit mat dësem Tippfeeler an eisem Code ze betruechten:

function isAdult(user) {
    return user.age > 18;
}

... oder wa mir de Wäert nëmmen 12 Joer getest hunn, oder nach méi schlëmm wa mir d'Behaaptung an eisem Test ausgoen.
De Mutatiounstest wäert tatsächlech fäeg sinn z'entdecken ob all Ausso sënnvoll getest gëtt. Et ass d'Standardmoossnam fir all aner Zorte vun Ofdeckung.

Aner Themen am Code

Loosst eis dann unhuelen datt mir keen onnéidege Code an eiser Applikatioun wëllen. Tatsächlech wäert all ontesten Deel eng Quell vu potenzielle Käfer sinn oder souguer zousätzlech Komplexitéit wann et net wesentlech ass.
Hei ass firwat Mutatiounstest e super Wee ass fir d'Relevanz vun esou Code ze testen:
if (someVariable !== null && someVariable.hasValue()) {}
Musse mir de Wäert kontrolléieren "wäert"? War d'Konditioun aus Gewunnecht dobäi? Et kéint heeschen datt mir net sécher sinn iwwer d'Variabel "e puer Variabel" a géif weider Analyse berechtegen. Mir kënnen net méi déif goen ouni et ze realiséieren. Mutatiounstest hëlleft eis och domat.

Mutatiounstester: Wat sinn se?

Fir Mängel an eisen Eenheetstester z'entdecken, gëtt et eng Léisung: Mutatiounstest.

Dës Technik gëtt méi Vertrauen an eis Tester. Mutatiounstest ass e relativ einfacht Konzept. Säi Prinzip ass de Quellcode ze mësshandelen andeems se se änneren fir z'iwwerpréiwen datt déi assoziéiert Tester deementspriechend feelen. Mängel (oder Mutatiounen) ginn automatesch an eise Code gesaat, an dann Tester lafen. Wann d'Tester versoen, da gëtt d'Mutatioun ëmbruecht. Wann d'Tester passéieren, dann huet d'Mutatioun iwwerlieft. An dësem Fall heescht et datt d'Tester net mat der Komplexitéit vum Code entspriechen an een oder méi vun hiren Aspekter net getest ginn. Dann kann d'Qualitéit vun eisen Tester aus dem Prozentsaz vun de Mutatiounen gemooss ginn.
An anere Wierder, mir lafen d'Eenheetstester op automatesch geännert Versioune vum Code. Wann d'Applikatiounscode ännert, sollt et aner Resultater produzéieren an d'Eenheetstester versoen. Wann en Eenheetstest an dëser Situatioun net feelt, kann et e Feeler an der Testsuite uginn.
Hei sinn d'Schrëtt fir dëst z'erreechen:

  • Run déi üblech Test Suite fir z'iwwerpréiwen datt all Tester gréng passéieren.
  • Änneren e puer Deeler vum getestene Code ier Dir d'Testsuite nach eng Kéier ausféiert.
  • Vergewëssert Iech datt Tester gescheitert hunn wéi erwaart nodeems de getestene Code geännert (mutéiert) ass.

Widderhuelen d'Schrëtt 2 an 3 sou laang wéi méiglech Mutatiounen bleiwen.
Loosst eis e konkret Beispill huelen: Denkt un e Mutant als eng zousätzlech Klass mat nëmmen enger Ännerung vum Originalcode. Dëst kann d'Ännerung vun engem logesche Bedreiwer an enger If Klausel sinn wéi hei ënnendrënner:
wann( a || b ) {…} => wann( a && b ) {…}
D'Detektioun an d'Oflehnung vun esou enger Ännerung duerch existéierend Tester gëtt als Mutant ëmbruecht. Mat enger perfekter Testsuite op der Plaz, géif kee Klassemutant iwwerliewen. Awer all méiglech Mutanten erstellen ass Ressourceintensiv, dofir ass et net méiglech dës Approche manuell an realen Szenarien z'erreechen.
Glécklecherweis sinn et Tools verfügbar fir Mutanten op der Flucht ze kreéieren an automatesch all Tester fir all eenzel auszeféieren. D'Transformatiounskreatioun baséiert op enger Rei vu Mutatiounsbedreiwer, déi genannt ginn fir typesch Programméierungsfehler z'entdecken. De Mutatiounsbedreiwer, dee benotzt gëtt fir de Code hei uewen z'änneren, gëtt den Konditiounsbedreiwer genannt.

An der Praxis

Dës Technik besteet also aus zwee Deeler: d'Generatioun vu Mutanten, dann d'Eliminatioun vun dësen.
Mutant Generatioun ass de Schrëtt fir mutant Klassen aus Quellklassen ze generéieren. Fir unzefänken, brauche mir de Geschäftscode op deem mir d'Relevanz vun eisen Tester bewäerten wëllen. Mir huelen dann eng Schwämm vu méigleche Mutatiounen, eng Mutatioun ass eng Ännerung vum Quellcode, sou wéi d'Aktioun vun engem Bedreiwer mat engem aneren z'ersetzen.
Hei sinn e puer Beispiller:

  • + gëtt -
  • * GËTT /
  • >= gëtt ==
  • richteg gëtt falsch.
  • läschen eng Instruktioun
  • etc.

Mir kënnen en arithmeteschen Ausdrock e op |e| änneren (ABS), ännert e relationalen arithmetesche Bedreiwer an en aneren (ROR), ännert e arithmetesche Bedreiwer an en aneren (AOR), ännert e boolesche Bedreiwer an en aneren (COR), ännert e bool / arithmeteschen Ausdrock andeems Dir − oder ¬ (UOI) addéiert, ännert e Variabel Numm vun engem aneren, ännert e Variablen Numm mat enger Konstant vum selwechten Typ, ännert eng Konstant duerch eng aner Konstant vum selwechten Typ ...
Déi aktuell Generatioun besteet aus all d'Instruktioune vum Code duerchzegoen a fir all eenzel, ze bestëmmen ob Mutatiounen applicabel sinn. Wann jo, wäert all Mutatioun en neie Mutant entstoen.
Fir déi folgend Ausso:

if (a > 8) { x = y+1 }

Mir kënnen déi folgend Mutanten betruechten:

 if (a < 8) { x = y+1 }
 if (a ≥ 8) { x = y+1 }
 if (a > 8) { x = y-1 }
 if (a > 8) { x = y }

Dëse Prozess ka séier Ressourceintensiv ginn. Wann de Code dee muss mutéiert ginn eng grouss Unzuel vun Instruktiounen enthält an den " Schwämm » vu méigleche Mutatiounen bedeitend ass, da klëmmt d'Zuel vun generéierte Mutanten ganz séier.
Wann de Mutantengeneratiounsprozess fäerdeg ass, ginn d'Mutanten bis den nächste Schrëtt gelagert: Eliminatioun!
Fir den zweeten Deel vum Prozess hu mir vill Mutanten generéiert déi mir net duerch d'Tester passéiere wëllen; d'Zil ass et sou vill wéi méiglech ze eliminéieren. Fir dëst ze maachen, ass eis Waff d'Verbesserung vun Eenheetstester.

opgelëscht

Fir e bestëmmte Mutant ginn et zwee méiglech Resultater, entweder d'Tester sinn ëmmer gréng, oder op d'mannst ee vun hinnen ass rout ginn.

Normalerweis wëlle mir d'Tester gréng sinn. Mä an deem Kontext siche mir no Rout. Tatsächlech, wéi mir virdru gesinn hunn, soll all Mutant op d'mannst ee vun den Eenheetstester falen. Wann op d'mannst ee vun den Tester feelt, beweist dëst datt se fäeg sinn Codemodifikatiounen z'entdecken an dofir méiglech Bugs ze vermeiden. Op der anerer Säit, wann all d'Tester gréng bleiwen, iwwerlieft de Mutant, sou datt et fir d'Ae vun eisen Tester onsichtbar bliwwen ass.
En iwwerliewende Mutant ass also d'Zeeche vun engem fehlenden Test!

Beschränkungen

Déi komplett Analyse vun eisem Code kann langweileg sinn. Wéi mir gesinn hunn, kann d'Zuel vun de Mutanten ganz séier eropgoen.
Op enger éischter Phas kënne mir zum Beispill 6000 Mutanten generéieren. Wärend der zweeter Testphase ginn méi wéi 98% vun hinnen eliminéiert, de Prozentsaz variéiert jee no der fréierer Qualitéit vun Ären Tester. Mir hunn nach 150 bis 200 Mutanten iwwreg.
Eng manuell Analyse vun all vun hinnen ass Zäit-opwänneg. Ausserdeem sinn eis Eenheetstester net eleng verantwortlech fir hir Iwwerliewe. Et kann en "äquivalente Mutant" optrieden: e Mutant deen d'Syntax vum Quellcode ännert, ouni seng Semantik z'änneren. Dës Aart vu Mutant verhënnert datt en Eenheetstest et erkennt.

while(...) {
    index++;
    if (index == 10)
    break;
}

Zum Beispill, eng Mutatioun vun " == "an" <= wäert eng gläichwäerteg Mutant produzéieren. Dëst Beispill wäert déiselwecht Ausgangskonditioun vun der Loop hunn.
Pre-Analyse vun Code Ofdeckung, Schafung vu Mutanten op der Flucht an all déi néideg Tester verbrauchen vill Zäit. Zum Beispill erhéicht e Code mat 350 Tester d'Ausféierungszäit vu véier am Verglach mat engem gewéinleche Laf.
Gitt dës Zuelen an aus praktesche Grënn, Mutatiounstester kënnen net sou dacks wéi Eenheetstester ausgefouert ginn. Dofir ass et wichteg e passenden Workflow ze fannen deen de beschte Kompromëss a punkto Effizienz bitt. Fir grouss Software Systemer kéint dëst bedeiten datt Mutatiounstesten op Nuetslafe limitéiert sinn.
Ier Dir se implementéiert, musst Dir an enger fortgeschratt Qualitéits Approche sinn. D'Tester mussen am Mëttelpunkt vun der Entwécklung gesat ginn, fir Resultater ze vermeiden déi ze voluminös sinn fir ze analyséieren. Wéi och ëmmer, wann Code Ofdeckung seng Grenzen erreecht huet, kann dëst eng gutt Approche sinn fir mat ze experimentéieren. Leider schéngen déi aktuell Tools net industrialiséiert genuch.

Mutatiounstest a Javascript

Mutatiounstester si vill besser bekannt a benotzt an der Welt vu Java oder an PHP. Wéi och ëmmer, zënter 2016 gëtt et e Wee fir Mutatiounstest a JavaScript auszeféieren dank Stryker Mutator. Et gëtt och Grunt-Mutatiounstesten, d'Majoritéit vum Quellcode vun deem ass am Prozess fir op Stryker migréiert ze ginn.
Hei ass de Link op de Github: http://stryker-mutator.github.io

Conclusioun

Dësen Artikel war eng séier Aféierung zum Mutatiounstest. Mir adresséiert Test Mutanten, appréciéiert déi direkt Relatioun tëscht mutant Taux an der Qualitéit vun enger bestehend Test Suite, an observéiert der Korrelatioun mat Code Ofdeckung.
Zënter Codeofdeckung ass net eng ganz zouverléisseg Metrik, Mutatiounstester sinn e séieren an einfache Wee fir d'Zouverlässegkeet vun Eenheetstester ze moossen. Mir förderen Mutatiounstester wou et e richtegt Thema ass: de Geschäftscode.
Alles an allem schéngt de Mutatiounstest wéi eng flott Ergänzung zu enger Rei vu Qualitéitssécherungsinstrumenter., baséiert op automatiséiert Tester. Dës Praxis ass zimlech rezent a JavaScript an nach ëmmer onbekannt. Et wäert interessant sinn d'Meenungen a Feedback vun fortgeschratt Benotzer ze liesen.
Aurélie Ambal, (@Souvir) JS Craftswoman @JS-Republic
[actionbox Faarf = "Standard" title = "" Beschreiwung ="JS-REPUBLIC Training gëtt vun Datadock referenzéiert.
Fannt all eis Trainingscoursen op eiser Websäit training.ux-republic.com:

  • UX Design
  • Agile
  • Javascript

” btn_label=”Eis Trainingen” btn_link=”http://training.ux-republic.com” btn_color=”primär” btn_size=”grouss” btn_icon=”Star” btn_external=”1″]