Ce este testarea mutațiilor? (Exemplu)

⚡ Rezumat inteligent

Testarea mutațiilor introduce în mod deliberat mici erori în codul sursă și apoi rulează suita de teste existentă pentru fiecare versiune defectă, măsurând dacă acele teste sunt suficient de puternice pentru a detecta schimbarea.

  • 🔘 Definiție: Un mutant este programul care poartă o modificare sintactică deliberată, iar uciderea lui dovedește că un test a detectat acea modificare.
  • ☑️ Procesul: Generați mutanți, rulați suita împotriva originalului și a mutantului, comparați rezultatele, apoi consolidați testele care au ratat erori.
  • ✅ Operators: OperaÎnlocuirea și modificarea expresiei și modificarea afirmațiilor produc cele trei familii principale de mutanți.
  • 🧪 Scor: Scorul de mutație este procentul de mutanți uciși și măsoară puterea aserțiunii, mai degrabă decât simpla execuție a unei linii.
  • 🛠️ scule: Huse Stryker Javascenariu, TypeScript, C# și Scala, în timp ce PIT modifică bytecode-ul JVM din Maven și Gradle construiește.
  • ⚠️ Pretul biletului: Fiecare mutant rulează din nou întreaga suită, așa că testarea mutațiilor este lentă, costisitoare și impracticabilă fără automatizare.

Testarea mutațiilor

Ce este testarea mutațiilor?

Testarea mutațiilor este un tip de testare software în care anumite instrucțiuni ale codului sursă sunt modificate sau mutate pentru a verifica dacă cazurile de testare pot găsi erori în codul sursă. Scopul testării mutațiilor este de a asigura calitatea cazurilor de testare în ceea ce privește robustețea, astfel încât acestea să eșueze în fața codului sursă mutat.

Schimbarea făcută într-un program mutant trebuie să fie menținută extrem de mică, astfel încât să nu afecteze obiectivul general al programului. Testarea mutațiilor este numită și o strategie de testare bazată pe erori, deoarece implică crearea deliberată a unei erori în program. Este o formă de Alb Box Testarea care se aplică în principal în timpul Testarea unității.

Testarea mutațiilor a fost propusă în 1971 într-o lucrare studențească de Richard Lipton și formalizată în lucrarea din 1978 „Hints on Test Data Selection” de DeMillo, Lipton și Sayward. A pierdut din avânt față de costul de calcul al vremii și de atunci a recâștigat teren pentru limbaje precum Java, C#, Python, JavaScript și XML.

Cum se execută testarea mutațiilor?

Următorii sunt pașii pentru a executa testarea mutațiilor, cunoscută și sub denumirea de analiză a mutațiilor:

Pasul 1: Erorile sunt introduse în codul sursă al programului prin crearea mai multor versiuni numite mutante. Fiecare mutant ar trebui să conțină o singură eroare, iar scopul este de a provoca eșecul versiunii mutante, ceea ce demonstrează eficacitatea cazurilor de testare.

Pasul 2: Cazurile de testare sunt aplicate programului original și, de asemenea, programului mutant. A Caz de testare ar trebui să fie adecvat și este ajustat pentru a detecta erorile într-un program.

Pasul 3: Comparați rezultatele programului original și ale programului mutant.

Pasul 4: Dacă programul original și programul mutant generează ieșiri diferite, atunci mutantul este eliminat de cazul de testare. Prin urmare, cazul de testare este suficient de bun pentru a detecta schimbarea dintre programul original și cel mutant.

Pasul 5: Dacă programul original și programul mutant generează același rezultat, mutantul este menținut în viață. În astfel de cazuri, trebuie create cazuri de testare mai eficiente care să elimine toți mutanții.

Diagrama de mai jos tracUrmează aceiași cinci pași, de la programul original, trecând prin generarea de mutanți, până la verdictul de ucis sau supraviețuitor.

Flux de lucru pentru testarea mutațiilor care prezintă programul original, mutanții generați, execuția testului și verdictul privind mutantul ucis sau viu

Cum se creează programe mutante?

O mutație nu este altceva decât o singură modificare sintactică adusă unei instrucțiuni de program. Fiecare program mutant ar trebui să difere de programul original cu exact o mutație.

Programul original Programul Mutant
Dacă (x>y)
Tipăriți „Bună ziua”
Altfel
Tipăriți „Bună”
Dacă (x
Tipăriți „Bună ziua”
Altfel
Tipăriți „Bună”

În perechea de mai sus, doar operatorul de comparație s-a modificat, însă un caz de test în care x este mai mare decât y afișează acum „Salut” în loc de „Salut”. Ilustrația arată acea modificare sintactică.

O modificare sintactică aplicată unei instrucțiuni de program pentru a produce un singur mutant

Ce trebuie schimbat într-un program mutant?

Există mai multe tehnici care pot fi utilizate pentru a genera programe mutante. Cele trei familii de mai jos acoperă majoritatea operatorilor de mutație incluși în instrumente.

Operaşi operatori de înlocuire Operatori de modificare a expresiilor Operatori de modificare a instrucțiunilor
Înlocuiți operandul cu un alt operand (x cu y sau y cu x) sau cu o valoare constantă. Înlocuirea unui operator sau inserarea unui operator nou într-o instrucțiune de program. Instrucțiunile programatice sunt modificate pentru a crea programe mutante.
Exemplu:
Dacă(x>y) înlocuiți valorile x și y
Dacă(5>y) înlocuiți x cu constanta 5
Exemplu:
Dacă(x==y)
Putem înlocui == cu >= și avem programul mutant ca
If(x>=y) și inserând ++ în instrucțiune
Dacă(x==++y)
Exemplu:
Ștergeți partea else dintr-o declarație if-else
Ștergeți întreaga instrucțiune if-else pentru a verifica cum se comportă programul

Câțiva operatori de mutație exemplificați:

  • GOTO înlocuirea etichetei
  • Înlocuire declarație de returnare
  • Ștergerea declarației
  • Inserarea operatorilor unari (cum ar fi – și ++)
  • Înlocuirea conectorului logic
  • Înlocuire comparabilă de nume de matrice
  • Eliminarea părții else a unei instrucțiuni if-else
  • Adăugarea sau înlocuirea operatorilor
  • Înlocuirea declarației prin modificarea datelor
  • Modificarea datelor pentru variabile
  • Modificarea tipurilor de date în program

Operatori care ating o condiție limită supraviețuiesc cel mai adesea, așa că rezultatele mutațiilor indică frecvent lacune în analiza valorii la limită.

Tipuri de testare a mutațiilor

In Inginerie SoftwareTestarea mutațiilor este clasificată fundamental în trei tipuri - mutație a afirmațiilor, mutație a valorii și mutație a deciziilor.

  • Mutația declarației – o instrucțiune este tăiată, lipită sau ștearsă, astfel încât rezultatul poate fi eliminarea unor linii de cod.
  • Mutația valorii – valorile parametrilor primari și ale constantelor sunt modificate, de exemplu, schimbarea unei limite a buclei sau a unui prag.
  • Mutație de decizie – instrucțiunile de control sunt modificate, de exemplu flipping un operator relațional sau negarea unei condiții.

Instrumentele își grupează operatorii sub aceste trei titluri, astfel încât familia care a produs un mutant supraviețuitor îi spune testerului ce tip de aserțiune lipsește. Un mutant de decizie supraviețuitor marchează de obicei o ramură netestată, care se suprapune cu testarea în buclă.

Automatizarea testării mutațiilor

Testarea mutațiilor consumă extrem de mult timp și este complicat de executat manual, așa că este recomandabil să se utilizeze instrumente de automatizare, care reduc și costurile. Un instrument de mutație compilează mutanții, programează rulările, înregistrează ce mutant a fost eliminat de fiecare test eșuat și raportează scorul.

Lista instrumentelor disponibile:

  • Stryker — un cadru open-source pentru testarea mutațiilor cu ediții pentru JavaScript și TypeScript (StrykerJS), C# și .NET (Stryker.NET) și Scala (Stryker4s).
  • PIT, scris și PITest — un sistem de testare a mutațiilor pentru Java și JVM-ul care modifică bytecode-ul compilat și se conectează la Maven și Gradle construiește alături JUnit.

Ambele rulează ca un pas de construire, deci aparțin aceleiași integrare continuă conductă ca și restul testarea automatizării pe.

Scorul de mutație

Scorul de mutație este definit ca procentul de mutanți uciși din numărul total de mutanți.

Scor mutație = (Mutanți uciși / Numărul total de mutanți) * 100

Formula este prezentată mai jos în forma în care o raportează majoritatea instrumentelor.

Formula scorului de mutație: împărțirea mutanților uciși la numărul total de mutanți și înmulțirea cu o sută

Cazurile de testare sunt descrise ca fiind adecvate pentru mutație atunci când scorul atinge 100%. În practică, numitorul trebuie să excludă mutanți echivalenți — mutanți a căror sintaxă modificată se comportă exact ca originalul, deci niciun test nu îi poate elimina. Prin urmare, instrumentele raportează mutanții eliminați împărțit la mutanții neechivalenți eliminați plus mutanții neechivalenți supraviețuitori și permit testerului să semnaleze echivalențele.

Rezultatele experimentale au arătat că testarea mutațiilor este o modalitate eficientă de a măsura adecvarea cazurilor de testare. Principalul dezavantaj este costul generării mutanților și al executării fiecărui caz de testare pentru fiecare dintre ei.

Testarea mutațiilor vs. Code Acoperire

Înalt acoperirea testului nu demonstrează teste puternice. Acoperirea liniilor și ramurilor înregistrează ce instrucțiuni au rulat, nu dacă ceva a fost verificat ulterior, astfel încât un test care apelează o metodă și nu afirmă nimic este totuși considerat acoperit. Testarea mutațiilor elimină această lacună, deoarece un mutant moare doar atunci când o aserțiune eșuează efectiv.

Aspect Code acoperire Scorul mutației
Ce măsoară Ce linii sau ramificații au executat testele Ce defecte injectate au detectat testele
Sensibil la afirmații Nu — un test cu zero aserțiuni adaugă în continuare acoperire Da — un mutant supraviețuiește atunci când nicio afirmație nu eșuează
Costul unei curse O rulare de testare instrumentată Un singur test per mutant supraviețuitor, deci mult mai lent
Utilizare tipică O portiță rapidă pentru fiecare commit O verificare periodică mai aprofundată a modulelor critice
Modul de eșec Acoperire 100% fără verificare reală Mutanți echivalenți care nu pot fi niciodată uciși

Cele două valori sunt complementare. Acoperirea denumește codul care nu a fost niciodată atins; scorul de mutație denumește codul atins care nu a fost niciodată verificat. Ambele alimentează aceleași informații. procesul de management al defectelor, alături de măsuri precum densitatea defectelor.

Avantajele testării mutațiilor

Următoarele sunt avantajele testării mutațiilor:

  • Este o abordare puternică pentru obținerea unei acoperiri ridicate a programului sursă.
  • Testează însăși suita de teste, pe care nicio altă tehnica de testare a software-ului face direct.
  • Testarea mutațiilor oferă dezvoltatorului de software un nivel bun de detectare a erorilor.
  • Metoda descoperă ambiguități în codul sursă și are capacitatea de a expune erori pe care execuțiile obișnuite nu le ating niciodată.
  • Mutanții supraviețuitori sunt acționabile: fiecare numește o linie specifică și o schimbare specifică pe care suita nu a reușit să le observe.
  • Clienții beneficiază de această testare, primind un sistem mai fiabil și mai stabil.

Dezavantajele testării mutațiilor

Pe de altă parte, următoarele sunt dezavantajele testării mutațiilor:

  • Testarea mutațiilor este extrem de costisitoare și consumatoare de timp, deoarece trebuie generat și compilat un număr mare de programe mutante.
  • Întrucât necesită mult timp, este corect să spunem că această testare nu poate fi realizată fără un instrument de automatizare.
  • Fiecare mutant este exersat de același număr de cazuri de testare ca și programul original, așa că o populație mare de mutanți trebuie rulată împotriva întregii suite de teste.
  • Mutanții echivalenți nu pot fi uciși prin niciun test, iar separarea lor de supraviețuitorii autentici necesită de obicei o revizuire manuală.
  • Deoarece metoda modifică codul sursă, nu este aplicabilă pentru Negru Box Testarea.

Când se utilizează testarea mutațiilor

Profilul de costuri de mai sus înseamnă că testarea mutațiilor este rareori executată pe o bază de cod întreagă la fiecare commit. Se amortizează singură acolo unde o eroare nedetectată este costisitoare, iar codul testat este suficient de mic pentru a muta rapid.

  • Logică critică pentru siguranță sau financiară — calcularea plăților, regulile fiscale și verificările autorizațiilor, unde un răspuns greșit silențios este mai rău decât un accident.
  • Suite cu acoperire suspect de mare — când acoperirea se apropie de 100%, dar defectele tot nu apar.
  • Codul vechi este refactorizat — rezultatele mutațiilor arată dacă testele existente ar detecta o regresie.
  • Biblioteci și componente partajate — o defecțiune la o unitate reutilizată component se multiplică pentru fiecare apelant.
  • Echipe care se antrenează dezvoltare bazată pe teste — scorul verifică dacă testele scrise mai întâi funcționează cu adevărat.

De obicei, nu merită să rulezi pe prototipuri de unică folosință, pe cod subțire sau generat fără logică de ramificare sau pe suite dominate de algoritmi lenti. teste de integrare care deja durează ore întregi pentru o singură trecere.

Prin urmare, majoritatea echipelor definesc rularea la fișierele modificate, stabilesc un prag pentru modulele importante și permit accesul mai larg. testarea regresiei suita transportă restul ciclul de viață al testării software.

Întrebări frecvente

Un mutant echivalent este o modificare care modifică sintaxa, dar nu și comportamentul, cum ar fi înlocuirea unei limite de buclă care nu este niciodată atinsă. Niciun test nu îl poate elimina, așa că trebuie semnalizat și exclus înainte ca scorul să fie considerat de încredere.

Nu există un număr universal. Echipele stabilesc de obicei un prag ridicat pentru modulele critice, cum ar fi logica de plată sau de securitate, și unul mai mic în alte părți. Urmărirea unui procent este mai puțin utilă decât revizuirea fiecărui mutant supraviețuitor în codul cu risc ridicat.

Acestea sunt cele două presupuneri pe care se bazează tehnica. Prima spune că programatorii scriu cod aproape corect, deci erorile reale sunt mici. A doua spune că testele care detectează erori mici detectează și erorile complexe construite din ele.

Restricționează mutația la fișierele modificate în ramura curentă, reutilizează datele de acoperire astfel încât să fie executate doar testele care ating un mutant, rulează mutanții în paralel și eșuează compilarea la o scădere a scorului în loc de o cifră absolută.

Modelele de învățare automată prevăd ce mutanți sunt susceptibili de a supraviețui, astfel încât rularea să poată fi redusă, să clasifice mutanții echivalenți probabili pentru revizuire și să genereze mutanți care seamănă cu defectele observate în istoricul proiectului, mai degrabă decât cu schimbări uniforme de operatori.

Da, pentru partea mecanică. Având în vedere un mutant supraviețuitor și metoda testată, Copilot elaborează aserțiunea lipsă sau testul de caz limită. Un recenzent trebuie să confirme în continuare că valoarea așteptată este corectă și nu este pur și simplu copiată din comportamentul curent.

Acesta auditează rezultatul. Dezvoltarea bazată pe teste produce teste înainte de cod, dar nimic nu garantează că acele teste sunt suficient de eficiente. O mutație periodică rulată pe aceleași module arată dacă ciclul roșu-verde a produs teste care eșuează cu adevărat la un răspuns greșit.

Nu. Injecția de erori corupe mediul de execuție și testarea fuzz furnizează date de intrare incorecte, ambele evaluând aplicația. Testarea mutațiilor modifică codul sursă și evaluează suita de teste, astfel încât obiectul evaluat este diferit.

Rezumați această postare cu: