Cos'è il test di mutazione? (Esempio)
⚡ Riepilogo intelligente
Il mutation testing introduce deliberatamente piccoli difetti nel codice sorgente e poi esegue la suite di test esistente su ogni versione difettosa, misurando se tali test sono sufficientemente robusti da rilevare la modifica.
Cos'è il test di mutazione?
Test di mutazione Il Mutation Testing è un tipo di test del software in cui determinate istruzioni del codice sorgente vengono modificate, o mutate, per verificare se i casi di test sono in grado di individuare errori nel codice sorgente. L'obiettivo del Mutation Testing è garantire la qualità dei casi di test in termini di robustezza, in modo che falliscano in presenza del codice sorgente mutato.
La modifica apportata a un programma mutante deve essere mantenuta estremamente piccola, in modo da non influenzare l'obiettivo generale del programma. Il test di mutazione è anche chiamato strategia di test basata sui difetti, perché prevede la creazione deliberata di un difetto nel programma. È una forma di Bianco Box Collaudo che viene applicato principalmente durante Test unitari.
Il Mutation Testing è stato proposto nel 1971 in un articolo studentesco di Richard Lipton e formalizzato nell'articolo del 1978 "Hints on Test Data Selection" di DeMillo, Lipton e Sayward. Ha perso slancio a causa del costo computazionale dell'epoca e da allora ha recuperato terreno per linguaggi come Java, C#, Python, JavaScript e XML.
Come eseguire il test di mutazione?
Di seguito sono riportati i passaggi per eseguire il test di mutazione, noto anche come analisi di mutazione:
Passo 1: I difetti vengono introdotti nel codice sorgente del programma creando numerose versioni chiamate mutanti. Ogni mutante dovrebbe contenere un singolo difetto e l'obiettivo è quello di far sì che la versione mutante fallisca, dimostrando così l'efficacia dei casi di test.
Passo 2: I casi di test vengono applicati al programma originale e anche al programma mutante. Test Case dovrebbe essere adeguato ed è ottimizzato per rilevare errori in un programma.
Passo 3: Confronta i risultati del programma originale e del programma mutante.
Passo 4: Se il programma originale e il programma mutante generano un output diverso, allora il mutante viene eliminato dal caso di test. Pertanto, il caso di test è sufficientemente valido per rilevare la differenza tra il programma originale e quello mutante.
Passo 5: Se il programma originale e il programma mutante generano lo stesso output, il mutante viene mantenuto in vita. In questi casi, è necessario creare casi di test più efficaci che eliminino tutti i mutanti.
Il diagramma sottostante tracSi tratta degli stessi cinque passaggi, dal programma originale, passando per la generazione dei mutanti, fino al verdetto di sopravvivenza o uccisione.
Come creare programmi mutanti?
Una mutazione non è altro che una singola modifica sintattica apportata a un'istruzione di programma. Ogni programma mutante deve differire dal programma originale per una sola mutazione.
| Programma originale | Programma mutante |
| Se (x>y) Stampa "Ciao" Altro Stampa "Ciao" |
Se (x Stampa "Ciao" Altro Stampa "Ciao" |
Nella coppia sopra riportata, è cambiato solo l'operatore di confronto, eppure un caso di test in cui x è maggiore di y ora stampa "Hi" invece di "Hello". L'illustrazione mostra che una singola modifica sintattica...
Cosa cambiare in un programma mutante?
Esistono diverse tecniche che possono essere utilizzate per generare programmi mutanti. Le tre famiglie seguenti coprono la maggior parte degli operatori di mutazione inclusi negli strumenti.
| Operaoperatori sostitutivi e | Operatori di modifica dell'espressione | operatori di modifica delle dichiarazioni |
| Sostituisci l'operando con un altro operando (x con y, o y con x) oppure con un valore costante. | Sostituire un operatore o inserirne uno nuovo in un'istruzione di programma. | Le istruzioni programmatiche vengono modificate per creare programmi mutanti. |
| Esempio: Se (x>y) sostituisci i valori x e y Se(5>y) sostituisci x con la costante 5 |
Esempio: Se(x==y) Possiamo sostituire == con >= e avere il programma mutante come If(x>=y) e inserendo ++ nell'istruzione Se(x==++y) |
Esempio: Elimina la parte else in un'istruzione if-else Elimina l'intera istruzione if-else per verificare il comportamento del programma. |
Alcuni esempi di operatori di mutazione:
- Sostituzione etichetta GOTO
- Sostituzione dell'istruzione di reso
- Cancellazione dichiarazione
- Inserimento di operatori unari (come – e ++)
- Sostituzione del connettore logico
- Sostituzione del nome di array comparabile
- Rimozione della parte else di un'istruzione if-else
- Aggiunta o sostituzione di operatori
- Sostituzione dell'istruzione modificando i dati
- Modifica dei dati per le variabili
- Modifica dei tipi di dati nel programma
Operai tori che toccano una condizione limite sopravvivono più spesso, quindi i risultati delle mutazioni spesso puntano indietro alle lacune in analisi del valore limite.
Tipi di test di mutazione
In Software EngineeringIl mutation testing si suddivide fondamentalmente in tre tipologie: mutazione delle istruzioni, mutazione dei valori e mutazione delle decisioni.
- Mutazione dell'istruzione – un'istruzione viene tagliata, incollata o eliminata, quindi il risultato potrebbe essere la rimozione di alcune righe di codice.
- Mutazione del valore – vengono modificati i valori dei parametri e delle costanti primarie, ad esempio cambiando il limite di un ciclo o una soglia.
- Mutazione della decisione – le istruzioni di controllo vengono modificate, ad esempio capovolgimentoping un operatore relazionale o la negazione di una condizione.
Gli strumenti raggruppano i loro operatori sotto queste tre intestazioni, quindi la famiglia che ha prodotto un mutante sopravvissuto dice al tester quale tipo di asserzione manca. Un mutante decisionale sopravvissuto di solito contrassegna un ramo non testato, che si sovrappone a test del ciclo.
Automazione dei test di mutazione
L'esecuzione manuale dei test di mutazione è estremamente dispendiosa in termini di tempo e complessa, pertanto è consigliabile utilizzare strumenti di automazione, che consentono anche di ridurre i costi. Uno strumento di test di mutazione compila i mutanti, pianifica le esecuzioni, registra quale mutante viene eliminato in caso di test fallito e riporta il punteggio.
Elenco degli strumenti disponibili:
- Stryker — un framework di test di mutazione open-source con edizioni per JavaScrittura e TypeScript (StrykerJS), C# e .NET (Stryker.NET) e Scala (Stryker4s).
- PIT, anche scritto PITest — un sistema di test delle mutazioni per Java e la JVM che modifica il bytecode compilato e si collega a Maven e Gradle costruisce a fianco JUnit.
Entrambi vengono eseguiti come fase di compilazione, quindi appartengono allo stesso integrazione continua conduttura come il resto del test di automazione on.
Punteggio di mutazione
Il punteggio di mutazione è definito come la percentuale di mutanti uccisi rispetto al numero totale di mutanti.
Punteggio mutazione = (mutanti uccisi/numero totale di mutanti) * 100
La formula è mostrata qui sotto nel formato in cui viene riportata dalla maggior parte degli strumenti.
I casi di test sono descritti come mutazione adeguata quando il punteggio raggiunge il 100%. In pratica il denominatore deve escludere mutanti equivalenti — mutanti la cui sintassi modificata si comporta esattamente come l'originale, quindi nessun test può eliminarli. Gli strumenti, pertanto, segnalano i mutanti eliminati divisi per i mutanti non equivalenti eliminati più quelli sopravvissuti, e lasciano al tester il compito di segnalare gli equivalenti.
I risultati sperimentali hanno dimostrato che il mutation testing è un metodo efficace per misurare l'adeguatezza dei casi di test. Lo svantaggio principale è rappresentato dal costo di generazione dei mutanti e dall'esecuzione di ogni caso di test su ciascuno di essi.
Test di mutazione vs Code Copertura
Alto copertura di prova Non dimostra la robustezza dei test. La copertura di riga e di ramo registra quali istruzioni sono state eseguite, non se qualcosa è stato verificato in seguito, quindi un test che chiama un metodo e non asserisce nulla viene comunque considerato coperto. Il mutation testing colma questa lacuna, perché un mutante muore solo quando un'asserzione fallisce effettivamente.
| Aspetto | Code copertura | punteggio di mutazione |
| Cosa misura | Quali linee o rami sono stati eseguiti i test | Quali guasti iniettati sono stati rilevati dai test |
| Sensibile alle affermazioni | No, un test senza asserzioni aggiunge comunque copertura. | Sì, un mutante sopravvive quando nessuna asserzione fallisce |
| Costo di una corsa | Una prova strumentata | Un test per ogni mutante sopravvissuto, finora molto più lento |
| Utilizzo tipico | Un gate veloce su ogni commit | Un controllo periodico più approfondito sui moduli critici |
| Modalità di fallimento | Copertura al 100% senza alcuna verifica reale | Mutanti equivalenti che non possono mai essere uccisi |
Le due metriche sono complementari. La copertura indica il codice che non è mai stato raggiunto; il punteggio di mutazione indica il codice raggiunto che non è mai stato controllato. Entrambe alimentano lo stesso processo di gestione dei difetti, insieme a misure quali densità dei difetti.
Vantaggi dei test di mutazione
Di seguito sono riportati i vantaggi del test di mutazione:
- Si tratta di un approccio efficace per ottenere un'elevata copertura del programma sorgente.
- Esegue il test della suite di test stessa, che nessun altro tecnica di test del software lo fa direttamente.
- Il mutation testing offre agli sviluppatori di software un buon livello di rilevamento degli errori.
- Il metodo individua le ambiguità nel codice sorgente e ha la capacità di rivelare difetti che le normali esecuzioni non rilevano mai.
- I mutanti sopravvissuti sono suscettibili di intervento: ognuno di essi identifica una linea specifica e una modifica specifica che la suite non è riuscita a rilevare.
- I clienti traggono vantaggio da questi test ricevendo un sistema più affidabile e stabile.
Svantaggi dei test di mutazione
D'altro canto, i seguenti sono gli svantaggi del test di mutazione:
- Il test di mutazione è estremamente costoso e richiede molto tempo, perché è necessario generare e compilare un gran numero di programmi mutanti.
- Poiché richiede molto tempo, si può affermare che questo tipo di test non può essere eseguito senza uno strumento di automazione.
- Ogni mutante viene sottoposto allo stesso numero di casi di test del programma originale, quindi è necessario eseguire un'ampia popolazione di mutanti sull'intera suite di test.
- I mutanti equivalenti non possono essere eliminati da alcun test e la loro separazione dai veri sopravvissuti richiede solitamente una revisione manuale.
- Poiché il metodo modifica il codice sorgente, non è applicabile a Nero Box Collaudo.
Quando utilizzare i test di mutazione
Il profilo dei costi sopra descritto implica che il Mutation Testing viene raramente eseguito sull'intera codebase a ogni commit. Si ripaga da solo quando un errore non rilevato è costoso e il codice da testare è sufficientemente piccolo da consentire una mutazione rapida.
- Logica critica per la sicurezza o finanziaria — calcolo dei pagamenti, norme fiscali e verifiche delle autorizzazioni, dove una risposta errata, anche se silenziosa, è peggio di un incidente.
- Suite con una copertura sospettamente elevata — quando la copertura si avvicina al 100% ma i difetti sfuggono comunque.
- Codice legacy in fase di refactoring — i risultati delle mutazioni rivelano se i test esistenti sarebbero in grado di individuare una regressione.
- Librerie e componenti condivisi — un difetto in un riutilizzato componente si moltiplica per ogni chiamante.
- Squadre in allenamento sviluppo basato su test — il punteggio verifica che i test scritti inizialmente svolgano un lavoro reale.
Di solito non vale la pena eseguire test su prototipi usa e getta, su codice debole o generato senza logica di ramificazione, o su suite dominate da codice lento test di integrazione che già richiedono ore per un singolo passaggio.
La maggior parte dei team quindi limita l'esecuzione ai file modificati, imposta una soglia per i moduli che contano e lascia che il più ampio test di regressione la suite trasporta il resto del Ciclo di vita del test del software.



