Tag: mutation-testing, testing, qa, coverage, stryker, pitest
Livello: avanzato
TL;DR: Valuta la reale efficacia dei test introducendo difetti intenzionali nel codice. Se i test passano nonostante il difetto, la test suite non è affidabile.
Il tool altera operatori o logica (es. cambia + in -, > in <) creando un "mutante".
Mutante ucciso (killed): un test fallisce. È il risultato desiderato.
Mutante sopravvissuto (survived): i test passano ignorando il difetto. Indica asserzioni mancanti o deboli.
Dimostra l'effettiva solidità dei test, superando l'illusione della pura code coverage.
Mutante equivalente: una mutazione sintattica che non altera il comportamento logico reale.
Altamente esigente a livello di CPU: ogni mutante richiede una nuova esecuzione isolata dei test.
Strumenti principali nel mercato: Stryker (ecosistema JS/TS, C#, Scala) e PIT (Java).
Q: Che differenza c'è tra code coverage e mutation testing?R: La coverage dice solo se una riga è stata eseguita. Il mutation testing verifica se i test falliscono correttamente se quella riga viene corrotta.
Q: Perché non bloccare la build al 100% di mutation score?R: Il costo computazionale è eccessivo e il rischio di mutanti equivalenti genera falsi positivi. Meglio puntare su run differenziali per Pull Request.
Q: Come tratti un mutante equivalente?R: Valuto se il codice originale può essere scritto in modo meno ambiguo. Altrimenti disabilito la mutazione specifica tramite configurazione.
Confidare ciecamente nel 100% di code coverage quando si hanno test poveri di asserzioni.
Applicare la mutazione all'intera codebase anziché confinarla ai moduli core e alla logica di business.
Sprecare ore per uccidere mutanti puramente tecnici ignorando l'affidabilità generale.
Dimenticare i timeout di test: mutanti su condizioni di uscita dei loop generano facilmente cicli infiniti.
# Esecuzione standard di Stryker in un progetto Node.js
npx stryker run
TypeScript
// 1. Codice originale
const isAdult = (age: number) => age >= 18;
// 2. Mutante generato dal framework (es. Conditionals Boundary)
const isAdult = (age: number) => age > 18;
// Se nessun test verifica l'età ESATTA di 18 anni, il mutante sopravvive.
[ ] Setup dell'esecuzione incrementale (diff basato su Git) per evitare colli di bottiglia in CI.
[ ] Disabilitazione granulare dei mutanti tramite commenti ignorati nel sorgente.
Stryker Mutator Documentation
PIT Mutation Testing Documentation