Mutation Testing ist eine Technik zur Bewertung der Testqualität, theoretisch begründet von Richard Lipton 1971 und weiterentwickelt von Richard DeMillo und Timothy Budd, die absichtlich kleine syntaktische Änderungen, Mutanten genannt, in den Quellcode einbringt. Schlägt ein Test fehl, ist der Mutant getötet; überlebende Mutanten weisen auf schwache Tests hin, es sei denn, es sind äquivalente Mutanten, die das Programmverhalten nicht ändern. Der Mutations-Score, der Anteil getöteter nicht äquivalenter Mutanten, fragt, ob die Tests gut genug sind, nicht nur, ob die Abdeckung hoch genug ist.
Mutation Testing
Details
- Auch bekannt als
-
Mutationsanalyse, Fehlerbasiertes Testen
Kernkonzepte:
- Testqualitätsbewertung
-
Bewertung, wie effektiv Tests Fehler erkennen
- Code-Mutationen
-
Absichtliches Einführen kleiner, syntaktischer Änderungen (Mutanten) in Quellcode
- Mutationsoperatoren
-
Regeln zur Erstellung von Mutanten (z.B.
>zu>=ändern, Boolean umkehren, Anweisung entfernen) - Getötete Mutanten
-
Mutationen, die durch fehlschlagende Tests erkannt wurden (gut)
- Überlebende Mutanten
-
Mutationen, die von Tests nicht erkannt wurden (zeigt Testschwäche an)
- Äquivalente Mutanten
-
Mutationen, die das Programmverhalten nicht ändern (Falsch-Positive)
- Mutations-Score
-
Prozentsatz getöteter Mutanten:
(getötet / (gesamt - äquivalent)) × 100% - Mutationen erster Ordnung
-
Einzelne atomare Änderung pro Mutant
- Mutationen höherer Ordnung
-
Mehrere kombinierte Änderungen
- Schwache Mutation
-
Test muss nur unterschiedlichen internen Zustand erzeugen
- Starke Mutation
-
Test muss unterschiedliche finale Ausgabe erzeugen
- Testadäquatheitskriterium
-
"Sind die Tests gut genug?" nicht nur "Ist die Abdeckung hoch genug?"
- Schlüsselvertreter
-
Richard Lipton (theoretische Grundlage, 1971), Richard DeMillo, Timothy Budd
Wichtige Werkzeuge:
-
PITest (Java)
-
Stryker (JavaScript/TypeScript, C#, Scala)
-
Mutmut (Python)
-
Infection (PHP)
-
Mull (C/C++)
Wann zu verwenden:
-
Bewertung der Testsuit-Qualität über Abdeckungsmetriken hinaus
-
Identifizierung von Lücken in Test-Assertions
-
Kritische Systeme, die hohes Testvertrauen erfordern
-
Ergänzung der Code-Abdeckung als Qualitätsmetrik
-
Refactoring von Legacy-Code mit bestehenden Tests
-
Lehre effektiver Testpraktiken
-
Kontinuierliche Verbesserung der Testeffektivität
Praktische Herausforderungen:
- Rechenkosten
-
N Mutationen × M Tests = teuer
- Äquivalente-Mutanten-Problem
-
Schwierig, funktional identische Mutanten automatisch zu erkennen
- Zeitinvestition
-
Kann bei großen Codebasen langsam sein
- Abhilfestrategien
-
Selektive Mutation, Mutations-Sampling, inkrementelle Analyse
Beziehung zu anderen Praktiken:
- Code-Abdeckung
-
Mutations-Testing zeigt, dass hohe Abdeckung ≠ gute Tests
- TDD
-
Starkes TDD erzeugt oft natürlich hohe Mutations-Scores
- Property-based Testing
-
Orthogonale, aber komplementäre Ansätze
- Fault Injection
-
Ähnliches Konzept, angewendet auf Produktionssysteme