Il tuo test suite dice di coprire l'85% del codice. Ma quanti di quei test fallirebbero se qualcuno introducesse un bug? Se non lo sai, stai solo contando le righe eseguite, non la qualità delle verifiche. Il mutation testing risponde a questa domanda in modo brutale: introduce errori nel tuo codice e vede se i test li catturano. Noi, di Meteora Web, lo usiamo sui progetti che contano, perché sappiamo che un bug in produzione costa più di qualsiasi suite di test. In questa guida vediamo come funziona Stryker, come leggerne i report e come integrarlo nel tuo workflow senza rallentare lo sviluppo.
Cosa misura il mutation testing che la copertura non vede?
La code coverage ti dice solo quante righe di codice vengono eseguite durante i test. Non ti dice se le asserzioni sono significative. Un test che chiama una funzione e non verifica il risultato aumenta la copertura, ma non protegge nulla. Il mutation testing va oltre: prende il tuo codice, lo modifica in piccoli modi — cambia un operatore, inverte una condizione, elimina una chiamata — e riesegue i test. Se i test non falliscono, hai trovato un mutante sopravvissuto: un bug che il tuo suite non avrebbe rilevato.
Esempio concreto: un test inutile che passa
Immagina una funzione che calcola lo sconto:
Sponsored Protocol
function calcolaSconto($prezzo, $percentuale) {
return $prezzo - ($prezzo * $percentuale / 100);
}
Un test che chiama questa funzione senza asserire nulla darà copertura al 100%. Stryker muta $prezzo - in $prezzo + e il test continua a passare. Risultato: mutante sopravvissuto. Il tuo test è carta straccia. Ecco perché la copertura da sola è una metrica ingannevole.
Come funziona Stryker e perché sceglierlo?
Stryker è il framework di mutation testing più maturo per JavaScript/TypeScript e PHP. Funziona con la maggior parte dei runner di test esistenti — Jest, Vitest, PHPUnit, Mocha — e si integra nei pipeline CI. Il suo motore applica decine di mutatori: cambia operatori aritmetici, logici, rimuove condizioni, altera stringhe, elimina chiamate di funzione. Per ogni mutante, riesegue i test e genera un report dettagliato.
Perché Stryker rispetto ad altri strumenti?
Abbiamo provato alternative come Infection per PHP e Pitest per Java. Stryker ha un ecosistema più uniforme: stessa interfaccia per JS e PHP, report HTML chiari, supporto per il test in parallelo. Con Stryker PHP e Stryker JS copri entrambi i mondi con una curva di apprendimento singola. Inoltre, il suo dashboard gratuito per progetti open source ti dà una storia delle metriche nel tempo.
Sponsored Protocol
Come si legge il report di Stryker per migliorare i test?
Il report HTML di Stryker è il cuore dell'analisi. Ogni mutante è classificato in tre modi: ucciso (i test falliscono), sopravvissuto (i test passano) e timeout (il test va in loop infinito — spesso un bug reale). La metrica chiave è il mutation score: percentuale di mutanti uccisi sul totale.
Priorità: quali mutanti sopravvissuti affrontare per primi?
Non tutti i sopravvissuti sono uguali. Un mutante che cambia > in >= in un controllo di accesso è critico. Uno che modifica una stringa di log è meno urgente. Con Stryker, filtra per tipo di mutatore e per file. Noi consigliamo di partire dai file con più logica di business — calcoli, autorizzazioni, gestione pagamenti — e ignorare i casi limite non rilevanti. L'obiettivo non è il 100%, ma un punteggio sopra l'80% nelle aree critiche.
Come integrare Stryker nel workflow di sviluppo senza rallentare?
Il mutation testing è computazionalmente pesante: per ogni mutante, riesegue l'intero test suite. Su progetti grandi, può richiedere ore. Ecco perché va eseguito in CI, non localmente a ogni commit. La strategia che usiamo noi: esegui Stryker su pull request mirate, limitando i file modificati. In questo modo, il feedback arriva in pochi minuti e non blocca il lavoro degli sviluppatori.
Sponsored Protocol
Configurazione minima per Stryker JS con Jest
{
"$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json",
"testRunner": "jest",
"coverageAnalysis": "perTest",
"mutate": ["src//*.js", "!src//*.test.js"],
"reporters": ["html", "clear-text", "progress"]
}
Questa configurazione dice a Stryker di mutare solo i file in src, escludendo i test. Il coverageAnalysis: perTest accelera l'esecuzione associando ogni test ai file che tocca.
Comando per eseguire Stryker in CI (GitHub Actions)
- name: Run mutation testing
run: npx stryker run
env:
STRYKER_DASHBOARD_API_KEY: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
Con questa pipeline, ogni pull request che modifica src riceve un report. Se il mutation score scende sotto la soglia configurata, la PR viene bloccata. Impostare una soglia iniziale del 70% sui moduli core è un buon punto di partenza.
Quali errori evitare quando si adotta il mutation testing?
Il primo errore è applicarlo a tutto il codice subito. Il risultato? Build lente e frustrazione. Il secondo è ignorare i mutanti sopravvissuti: se non li analizzi, lo strumento diventa rumore. Il terzo è scrivere test che uccidono i mutanti ma non verificano il comportamento reale — per esempio, test che controllano solo l'implementazione interna. Noi abbiamo visto team aggiungere asserzioni inutili solo per alzare il punteggio. Ricorda: il mutation testing è un mezzo per trovare buchi nei test, non un fine.
Sponsored Protocol
Come impostare una soglia realistica
Non esiste una percentuale magica. Per un e-commerce, il modulo pagamenti dovrebbe stare sopra il 90%. Per un blog, il 70% è accettabile. Inizia con una soglia bassa, monitora i report e alzala gradualmente. Il dashboard di Stryker ti mostra l'andamento nel tempo, così puoi vedere se stai migliorando o se i nuovi test sono solo fuffa.
Mutation testing e TDD: come si completano?
Se pratichi il Test-Driven Development, il mutation testing è il tuo alleato. Scrivere prima il test, poi il codice, produce test che nascono per verificare un comportamento. Stryker ti dice se quel test è abbastanza forte. Lo vediamo spesso: un test che sembra solido, ma un mutante sopravvissuto rivela che manca un caso limite. È un feedback che il TDD da solo non ti dà.
Strumenti alternativi e quando usarli
Oltre a Stryker, esistono Infection per PHP e Pitest per Java. Se il tuo progetto è PHP puro, Infection è maturo e veloce. Ma se lavori in un ambiente misto, Stryker ti dà un'unica interfaccia. Noi, di Meteora Web, usiamo Stryker per i progetti Laravel e Vue, e Infection per i clienti con codebase PHP legacy. La scelta dipende dal tuo stack, ma il concetto è identico: misurare la qualità dei test, non la quantità.
Sponsored Protocol
Cosa fare adesso
Ecco tre azioni concrete per partire oggi:
- Installa Stryker nel tuo progetto con
npm install --save-dev @stryker-mutator/coree configura il runner adatto (Jest, Vitest, PHPUnit). - Esegui Stryker su un modulo critico — ad esempio la logica di pagamento o autenticazione — e analizza i mutanti sopravvissuti. Scrivi test aggiuntivi per i casi mancanti.
- Integra Stryker in CI con una soglia minima di mutation score per le pull request. Imposta il dashboard per tracciare l'andamento.
Il mutation testing non è un lusso. È l'unico modo per sapere se i tuoi test valgono qualcosa. E se vuoi vederlo applicato su un progetto reale, dai un'occhiata alla nostra guida sul testing del software per capire dove si inserisce nella piramide. Per approfondire la documentazione ufficiale, consulta Stryker Docs.