Mutation Testing con Stryker.NET
Mutation Testing con Stryker.NET
Come testare la qualità dei tuoi test in ambiente .NET
Indice dei Contenuti Mutation Testing con Stryker.NET
- Che cos’è il Mutation Testing?
- Perché usare Stryker.NET?
- Installazione e configurazione: mini guida pratica
- Tipi di mutazioni supportate
- Interpretare i risultati: killed, survived, timeout
- Integrazione nel pipeline CI/CD
- Best practice, pro e contro
- Formazione continua: la chiave del successo
- Conclusioni e contatti
Se sei uno sviluppatore .NET, avrai già sentito parlare di code coverage: quella metrica che misura quante righe di codice vengono eseguite dai tuoi test. Ma attenzione: avere il 90% di copertura non significa necessariamente avere test di qualità. I tuoi test potrebbero passare anche se la logica applicativa fosse completamente sbagliata. È qui che entra in gioco il mutation testing — e in ambito .NET, lo strumento di riferimento è Stryker.NET.
1. Che cos’è il Mutation Testing?
Il mutation testing è una tecnica avanzata di verifica della qualità dei test unitari. Il concetto è semplice: invece di testare il codice applicativo, proviamo a “testare i test” introducendo appositamente dei piccoli bug nel codice sorgente — chiamati mutanti — e verificando che i test esistenti li rilevino.
In pratica, uno strumento di mutation testing modifica automaticamente il codice (ad esempio cambia un operatore > con >=, oppure un && con ||), poi riesegue la suite di test. Se i test falliscono, il mutante è stato “ucciso” (killed): significa che i test sono abbastanza robusti da rilevare quella variazione. Se i test continuano a passare nonostante il bug introdotto, il mutante è “sopravvissuto” (survived): è un campanello d’allarme che indica una lacuna nei test.
Questo approccio supera i limiti del tradizionale code coverage, che misura solo quante linee vengono eseguite, non se vengono effettivamente verificate con asserzioni significative.
2. Perché usare Stryker.NET?
Stryker.NET è lo strumento ufficiale di mutation testing per l’ecosistema .NET. Fa parte della famiglia Stryker Mutator, nata nel 2018 proprio per colmare un vuoto nel panorama .NET rispetto ad altri linguaggi come Java (che ha PIT) o JavaScript (che ha Stryker JS).
Secondo la documentazione ufficiale Microsoft, Stryker.NET esegue automaticamente le mutazioni nel codice, lancia i test e genera un report HTML dettagliato con i risultati. La versione più recente disponibile su NuGet (aprile 2026) è la 4.14.1.
Ecco alcune ragioni per cui dovresti considerarlo nel tuo progetto:
- Identifica test deboli o incompleti che il solo code coverage non rivela
- Forza il team a scrivere asserzioni precise e mirate
- Produce report HTML visivi e interattivi, facili da leggere
- Supporta l’integrazione con Azure Pipelines, GitHub Actions e altri strumenti CI/CD
- Compatibile con .NET Core, .NET 5/6/7/8/9 e .NET Framework
- Altamente configurabile tramite file JSON
3. Installazione e configurazione: mini guida pratica
3.1 Installazione globale
Il modo più rapido per iniziare è installare Stryker.NET come strumento globale .NET. Apri il terminale e lancia:
dotnet tool install -g dotnet-stryker
Per aggiornarlo in futuro, usa:
dotnet tool update -g dotnet-stryker
3.2 Installazione locale al progetto (consigliata in team)
Per garantire che tutti i membri del team usino la stessa versione, è preferibile l’installazione locale:
# Nella cartella del progetto di testdotnet new tool-manifestdotnet tool install dotnet-stryker
Il file dotnet-tools.json generato può essere versionato su Git, così ogni sviluppatore avrà automaticamente accesso alla versione corretta.
3.3 Prima esecuzione
Posizionati nella directory del progetto di test e avvia Stryker.NET:
dotnet stryker
Per la maggior parte dei progetti .NET Core non è necessaria alcuna configurazione aggiuntiva: Stryker trova autonomamente il progetto sorgente da mutare. Al termine, trovi il report HTML nella cartella StrykerOutput.
3.4 File di configurazione stryker-config.json
Per un controllo più preciso, crea il file stryker-config.json nella root del progetto di test. Esempio di configurazione avanzata:
{ "stryker-config": { "threshold-high": 80, "threshold-low": 60, "break-at": 50, "ignore-mutations": ["string"], "ignore-methods": ["*Logs", "*ToString"], "mutate": [ "!**/Migrations/**", "!**/*.Designer.cs" ] }}
Le opzioni principali:
- threshold-high / threshold-low: soglie per colorare il report (verde/giallo/rosso)
- break-at: se il mutation score scende sotto questa soglia, Stryker esce con codice di errore (utile in CI/CD)
- ignore-mutations: esclude certi tipi di mutazione rumorosi o non rilevanti
- mutate: esclude file o cartelle dal processo (es. migrazioni EF Core, file autogenerati)
4. Tipi di mutazioni supportate
Stryker.NET supporta numerose categorie di mutazioni. Ecco le principali:
| Tipo | Descrizione | Esempio |
| Equivalence | Sostituisce un operatore con uno equivalente | x < y diventa x <= y |
| Arithmetic | Sostituisce operatori aritmetici | x + y diventa x – y |
| Logical | Inverte operatori logici | x && y diventa x || y |
| String | Svuota le stringhe letterali | “testo” diventa “” |
| Conditional | Inverte condizioni booleane | true diventa false |
| Null coalescing | Modifica operatori di null-check | a ?? b viene alterato |
La lista completa delle mutazioni supportate è disponibile nella documentazione ufficiale: stryker-mutator.io/docs/stryker-net/mutations.
5. Interpretare i risultati: killed, survived, timeout
Dopo l’esecuzione, Stryker.NET classifica ogni mutante in tre categorie:
- Killed (ucciso): il test ha rilevato il mutante e fallito. Ottimo risultato! Significa che i test sono sufficientemente precisi.
- Survived (sopravvissuto): il test non ha rilevato il bug introdotto. Questo è un punto critico: bisogna aggiungere o migliorare i test in quell’area.
- Timeout: la mutazione ha generato un loop infinito o un percorso di esecuzione molto lento. Richiede analisi della logica o aumento del timeout configurato.
Il Mutation Score è la percentuale di mutanti uccisi sul totale. Un valore dell’80% o superiore è generalmente considerato un buon punto di partenza per la maggior parte dei progetti aziendali. Non perseguire il 100% a tutti i costi: concentrati sulle aree critiche per il business.
Esempio pratico: considera questo metodo e il relativo test iniziale, tratto dalla documentazione Microsoft:
// Codice sorgentepublic decimal CalculatePrice(decimal price, decimal discountPercent){ if (price <= 0) throw new ArgumentException("Price must be greater than zero.");
if (discountPercent < 0 || discountPercent > 100) throw new ArgumentException("Discount percent must be between 0 and 100.");
var discount = price * (discountPercent / 100); return Math.Round(price - discount, 2);}
Un test iniziale che verifica solo il caso “happy path” lascerà sopravvivere molti mutanti sulle condizioni di boundary (es. price == 0, discountPercent == 100). Stryker.NET li individuerà tutti, guidandoti verso test più robusti come:
[Fact]public void InvalidPrice_ShouldThrowExceptionWithCorrectMessage(){ var calculator = new PriceCalculator(); // Cambiato da -10 a 0 per coprire il boundary price <= 0 var ex = Assert.Throws<ArgumentException>( () => calculator.CalculatePrice(0, 10)); Assert.Equal("Price must be greater than zero.", ex.Message);}
Con questo approccio iterativo, esegui Stryker, analizza i mutanti sopravvissuti, migliora i test, ripeti, la qualità della tua suite cresce in modo misurabile e continuo.
6. Integrazione nelle pipeline CI/CD
Stryker.NET si integra facilmente in Azure Pipelines o GitHub Actions. Grazie all’opzione break-at nel file di configurazione, il tool restituisce un exit code non zero se il mutation score scende sotto la soglia definita, bloccando automaticamente il merge o il deploy.
Esempio di step in un file GitHub Actions (.yml):
- name: Run Mutation Testing run: | cd tests/MyApp.Tests dotnet stryker # Il pipeline si blocca se mutation score < break-at (es. 50)
Un suggerimento pratico: poiché il mutation testing è computazionalmente pesante (esegue la suite di test centinaia di volte), valuta di configurarlo come job parallelo o schedulato (es. notturno), separato dagli step più rapidi di unit test e linting. Su codebase grandi, puoi usare l’opzione mutate per limitare l’analisi ai soli file modificati nella PR.
7. Best practice, pro e contro
Best Practice
- Inizia dai moduli critici: non applicare il mutation testing a tutto il progetto in una volta. Parti dalle classi con logica di business più delicata.
- Usa il file stryker-config.json: versiona la configurazione in Git per garantire consistenza nel team.
- Escludi il codice autogenerato: migrazioni EF Core, file .Designer.cs e simili vanno esclusi per non inquinare i risultati.
- Non puntare al 100%: un mutation score tra 70-85% è generalmente ottimale per progetti enterprise. Sopra l’85% il ritorno diminuisce.
- Integra progressivamente nel CI/CD: inizia con soglie basse (es. break-at: 40) e alzale nel tempo man mano che il team migliora la suite.
- Affianca al code coverage, non sostituirlo: i due strumenti si completano a vicenda.
| Pro | Contro |
| Rileva test superficiali che il coverage non vede | Esecuzione lenta su codebase grandi |
| Forza asserzioni precise e significative | Può generare falsi allarmi (mutanti equivalenti) |
| Report HTML interattivi e dettagliati | Curva di apprendimento iniziale per il team |
| Integrazione nativa con Azure Pipelines e GitHub Actions | Non adatto a test di integrazione o E2E |
| Compatibile con xUnit, NUnit, MSTest | Richiede disciplina nella configurazione e manutenzione |
| Open source, gratuito, attivamente mantenuto | Può rallentare il CI se non ottimizzato correttamente |
8. Formazione continua: la chiave del successo
Il mercato del software è in continua e rapida evoluzione. Nuovi framework, nuove pratiche DevOps, nuovi standard di qualità emergono ogni anno. In questo contesto, l’unico modo per mantenere il proprio team competitivo e aggiornato è investire in formazione continua.
Conoscere strumenti come Stryker.NET non basta: per sfruttarli al meglio è necessario comprenderli a fondo nel contesto dell’intero ciclo di sviluppo .NET, dalla scrittura di test unitari efficaci, alla gestione della CI/CD pipeline, fino all’integrazione con Azure DevOps.
Per questo InnovaFormazione offre percorsi di formazione professionale dedicati a sviluppatori e team IT:
- Corsi Microsoft .NET: percorsi completi su C#, ASP.NET Core, Entity Framework, testing e molto altro.
- Corsi Automation Testing: tecniche avanzate di test automation, mutation testing, BDD, integrazione CI/CD.
Grazie al Fondo Interprofessionale Fondimpresa, le aziende possono accedere a formazione finanziata per i propri dipendenti, abbattendo significativamente i costi. InnovaFormazione supporta le imprese nella gestione di tutto l’iter burocratico per l’accesso ai fondi.
9. Conclusioni
Il mutation testing con Stryker.NET rappresenta un salto di qualità nella verifica della robustezza dei test unitari in ambiente .NET. Non si tratta di sostituire le pratiche esistenti, come il code coverage o i test di integrazione, ma di affiancarle con uno strumento che risponde alla domanda fondamentale: “I miei test rileverebbero davvero un bug?”
In un mercato in cui la qualità del software è un differenziale competitivo, adottare strumenti come Stryker.NET è una scelta strategica. Ma l’adozione di nuovi strumenti richiede competenze aggiornate e una cultura della qualità diffusa in tutto il team. La formazione continua non è un costo: è un investimento sul capitale umano e sulla competitività dell’azienda.
Vuoi portare il tuo team al livello successivo? Scopri i nostri corsi dedicati. Visiona il catalogo completo QUI.
Per informazioni sui corsi, richiesta di preventivi e accesso ai finanziamenti Fondimpresa, contattaci:
Email: info@innovaformazione.net
Tel: 347 101 2275 — Dario Carrassi
Sito: innovaformazione.net
Per altri articoli tecnici di settore consigliamo di navigare sul nostro blog QUI.
Articoli correlati
Claude Code e Migrazioni SAP
Claude Code controllo remoto
Opportunità Carriera Contabilità SAP
Guida SIA AI
Guida Dual LLM Verification
