Was ist ein Mutationstest? (Beispiel)
⚡ Intelligente Zusammenfassung
Beim Mutation Testing werden absichtlich kleine Fehler in den Quellcode eingeführt und anschließend die bestehende Testsuite gegen jede fehlerhafte Version ausgeführt, um zu messen, ob diese Tests ausreichend sind, um die Änderung zu erkennen.
Was ist ein Mutationstest?
Mutationstests Mutationstests sind eine Art Softwaretest, bei dem bestimmte Anweisungen des Quellcodes verändert (mutiert) werden, um zu überprüfen, ob die Testfälle Fehler im Quellcode finden können. Ziel des Mutationstests ist es, die Robustheit der Testfälle sicherzustellen, sodass sie bei verändertem Quellcode fehlschlagen.
Die in einem mutierten Programm vorgenommene Änderung muss extrem gering sein, damit sie das Gesamtziel des Programms nicht beeinträchtigt. Mutationstests werden auch als fehlerbasierte Teststrategie bezeichnet, da sie das gezielte Erzeugen eines Fehlers im Programm beinhalten. Es handelt sich um eine Form des Mutationstests. Weiß Box Tests das hauptsächlich angewendet wird während Unit Tests.
Mutation Testing wurde 1971 in einer studentischen Arbeit von Richard Lipton vorgeschlagen und 1978 in der Arbeit „Hints on Test Data Selection“ von DeMillo, Lipton und Sayward formalisiert. Aufgrund des damaligen Rechenaufwands verlor es an Bedeutung, hat aber seither für Sprachen wie … wieder an Relevanz gewonnen. Java, C#, Python, JavaSkript und XML.
Wie führt man einen Mutationstest durch?
Im Folgenden sind die Schritte zur Durchführung eines Mutationstests, auch Mutationsanalyse genannt, aufgeführt:
Schritt 1: Fehler werden in den Quellcode des Programms eingeführt, indem zahlreiche Versionen, sogenannte Mutanten, erstellt werden. Jede Mutante sollte genau einen Fehler enthalten, und das Ziel ist es, die Mutantenversion zum Absturz zu bringen, wodurch die Wirksamkeit der Testfälle demonstriert wird.
Schritt 2: Die Testfälle werden sowohl auf das Originalprogramm als auch auf das mutierte Programm angewendet. Testfall sollte ausreichend sein und ist darauf ausgelegt, Fehler in einem Programm zu erkennen.
Schritt 3: Vergleichen Sie die Ergebnisse des Originalprogramms und des mutierten Programms.
Schritt 4: Wenn das Originalprogramm und das mutierte Programm unterschiedliche Ausgaben erzeugen, wird das mutierte Programm durch den Testfall beendet. Daher ist der Testfall ausreichend, um die Änderung zwischen dem Originalprogramm und dem mutierten Programm zu erkennen.
Schritt 5: Wenn das Originalprogramm und das mutierte Programm die gleiche Ausgabe erzeugen, bleibt die mutierte Version aktiv. In solchen Fällen müssen effektivere Testfälle erstellt werden, die alle mutierten Versionen eliminieren.
Das untenstehende Diagramm tracEs sind immer die gleichen fünf Schritte, vom ursprünglichen Programm über die Erzeugung von Mutanten bis hin zum Urteil, ob man getötet wurde oder überlebt hat.
Wie erstellt man Mutantenprogramme?
Eine Mutation ist nichts anderes als eine einzelne syntaktische Änderung an einer Programmanweisung. Jedes mutierte Programm sollte sich vom Originalprogramm durch genau eine Mutation unterscheiden.
| Ursprüngliches Programm | Mutantenprogramm |
| Wenn (x>y) Drucken Sie „Hallo“ Else Drucken Sie „Hallo“ |
Wenn (x Drucken Sie „Hallo“ Else Drucken Sie „Hallo“ |
Im obigen Beispielpaar hat sich lediglich der Vergleichsoperator geändert. Dennoch wird in einem Testfall, in dem x größer als y ist, nun „Hi“ anstelle von „Hello“ ausgegeben. Die Abbildung verdeutlicht diese eine syntaktische Änderung.
Was muss in einem Mutantenprogramm geändert werden?
Es gibt verschiedene Techniken zur Erzeugung von Mutationsprogrammen. Die drei unten aufgeführten Familien decken die meisten Mutationsoperatoren ab, die in den Tools standardmäßig enthalten sind.
| Operaund Ersatzbetreiber | Ausdrucksmodifikationsoperatoren | Operatoren zur Änderung von Anweisungen |
| Ersetzen Sie den Operanden durch einen anderen Operanden (x durch y oder y durch x) oder durch einen konstanten Wert. | Einen Operator in einer Programmanweisung ersetzen oder einen neuen Operator einfügen. | Programmatische Anweisungen werden geändert, um mutierte Programme zu erstellen. |
| Ejemplo: Wenn(x>y) ersetzen Sie die x- und y-Werte Wenn(5>y) ersetze x durch die Konstante 5 |
Ejemplo: Wenn(x==y) Wir können == durch >= ersetzen und das mutierte Programm wie folgt erhalten: If(x>=y) und Einfügen von ++ in die Anweisung Wenn(x==++y) |
Ejemplo: Löschen Sie den else-Teil in einer if-else-Anweisung Löschen Sie die gesamte if-else-Anweisung, um das Verhalten des Programms zu überprüfen. |
Einige Beispiele für Mutationsoperatoren:
- GOTO-Label-Ersatz
- Ersatz der Rückgabeerklärung
- Löschung der Anweisung
- Einfügung unärer Operatoren (wie – und ++)
- Austausch des logischen Connectors
- Vergleichbarer Array-Namensersatz
- Entfernen des else-Teils einer if-else-Anweisung
- Hinzufügen oder Ersetzen von Bedienern
- Anweisungsersetzung durch Änderung der Daten
- Datenmodifikation für die Variablen
- Änderung von Datentypen im Programm
OperaTors, die eine Randbedingung berühren, überleben am häufigsten, daher weisen Mutationsergebnisse häufig auf Lücken in zurück. Grenzwertanalyse.
Arten von Mutationstests
In Software EngineeringMutationstests lassen sich grundsätzlich in drei Typen unterteilen: Anweisungsmutation, Wertmutation und Entscheidungsmutation.
- Aussagemutation – Eine Anweisung wird ausgeschnitten, eingefügt oder gelöscht, sodass das Ergebnis die Entfernung einiger Codezeilen sein kann.
- Wertmutation – die Werte primärer Parameter und Konstanten werden verändert, beispielsweise durch die Änderung einer Schleifengrenze oder eines Schwellenwerts.
- Entscheidungsmutation – Kontrollanweisungen werden geändert, zum Beispiel umkehrenping ein relationaler Operator oder die Negation einer Bedingung.
Die Werkzeuge gruppieren ihre Operatoren unter diesen drei Kategorien, sodass die Familie, die eine überlebende Mutante erzeugt hat, dem Tester mitteilt, welche Art von Assertion fehlt. Eine überlebende Entscheidungsmutante markiert üblicherweise einen ungetesteten Zweig, der sich mit überschneidet. Schleifentest.
Automatisierung von Mutationstests
Mutationstests sind manuell extrem zeitaufwändig und kompliziert, daher empfiehlt sich der Einsatz von Automatisierungstools, die zudem Kosten sparen. Ein Mutationstest-Tool kompiliert die Mutanten, plant die Testläufe, protokolliert, welche Mutante durch jeden fehlgeschlagenen Test beendet wurde, und gibt das Ergebnis aus.
Liste der verfügbaren Werkzeuge:
- Stryker — ein Open-Source-Mutationstest-Framework mit Editionen für JavaDrehbuch und TypeScript (StrykerJS), C# und .NET (Stryker.NET) sowie Scala (Stryker4s).
- PIT, auch PITest geschrieben – ein Mutationstestsystem für Java und die JVM, die kompilierten Bytecode verändert und sich in Maven einbindet und Gradle baut neben JUnit.
Beide werden als Build-Schritt ausgeführt, gehören also in denselben Ordner. kontinuierliche integration Pipeline wie der Rest der Automatisierungstests Suite.
Mutations-Score
Der Mutationswert ist definiert als der Prozentsatz der getöteten Mutanten bezogen auf die Gesamtzahl der Mutanten.
Mutationspunktzahl = (getötete Mutanten / Gesamtzahl der Mutanten) * 100
Die Formel ist unten in der Form dargestellt, in der sie die meisten Tools ausgeben.
Testfälle gelten als mutationsadäquat, wenn die Punktzahl 100 Prozent erreicht. In der Praxis muss der Nenner bestimmte Werte ausschließen. äquivalente Mutanten Mutanten, deren veränderte Syntax sich exakt wie das Original verhält, können von keinem Test eliminiert werden. Daher melden die Tools die Anzahl der eliminierten Mutanten geteilt durch die Summe der eliminierten und überlebenden nicht-äquivalenten Mutanten und überlassen es dem Tester, Äquivalente zu kennzeichnen.
Experimentelle Ergebnisse haben gezeigt, dass Mutationstests eine effektive Methode sind, um die Eignung von Testfällen zu messen. Der Hauptnachteil besteht in den Kosten für die Generierung der Mutanten und die Ausführung jedes Testfalls gegen jede einzelne Mutante.
Mutationstests vs. Code Abdeckung
Hoch Testabdeckung Das beweist keine aussagekräftigen Tests. Zeilen- und Zweigabdeckung protokollieren lediglich, welche Anweisungen ausgeführt wurden, nicht aber, ob anschließend etwas verifiziert wurde. Daher gilt ein Test, der eine Methode aufruft und nichts überprüft, dennoch als abgedeckt. Mutationstests schließen diese Lücke, da ein Mutant nur dann abbricht, wenn eine Assertion tatsächlich fehlschlägt.
| Aspekt | Code Berichterstattung | Mutationswert |
| Was es misst | Welche Zeilen oder Zweige wurden die Tests ausgeführt? | Welche Fehler wurden durch die Tests aufgedeckt? |
| Empfindlich gegenüber Behauptungen | Nein – ein Test ohne Assertions erhöht trotzdem die Testabdeckung. | Ja – ein Mutant überlebt, wenn keine Behauptung fehlschlägt. |
| Kosten eines Laufs | Ein instrumentierter Testlauf | Ein Testlauf pro überlebendem Mutanten, bisher also deutlich langsamer. |
| Typische Verwendung | Ein schneller Check bei jedem Commit | Eine eingehendere regelmäßige Überprüfung kritischer Module |
| Fehlermodus | 100-prozentige Abdeckung ohne wirkliche Überprüfung | Äquivalente Mutanten, die niemals getötet werden können |
Die beiden Metriken ergänzen sich. Die Codeabdeckung erfasst den Code, der nie ausgeführt wurde; der Mutations-Score erfasst den erreichten Code, der nie überprüft wurde. Beide fließen in dieselbe Datenbank ein. Fehlermanagementprozess, zusammen mit Maßnahmen wie Defektdichte.
Vorteile von Mutationstests
Im Folgenden sind die Vorteile von Mutationstests aufgeführt:
- Es handelt sich um einen leistungsstarken Ansatz, um eine hohe Abdeckung des Quellprogramms zu erreichen.
- Es testet die Testsuite selbst, was kein anderer kann. Softwaretestverfahren tut es direkt.
- Mutationstests bieten Softwareentwicklern ein hohes Maß an Fehlererkennung.
- Die Methode deckt Unklarheiten im Quellcode auf und hat die Fähigkeit, Fehler aufzudecken, die bei normalen Programmläufen nie gefunden werden.
- Die überlebenden Mutanten sind angreifbar: Jeder von ihnen benennt eine bestimmte Zeile und eine bestimmte Änderung, die die Suite nicht bemerkt hat.
- Von diesen Tests profitieren die Kunden, indem sie ein zuverlässigeres und stabileres System erhalten.
Nachteile von Mutationstests
Auf der anderen Seite ergeben sich folgende Nachteile beim Mutationstest:
- Mutationstests sind extrem kostspielig und zeitaufwändig, da eine große Anzahl von mutierten Programmen generiert und kompiliert werden muss.
- Da dieser Vorgang zeitaufwändig ist, kann man mit Fug und Recht behaupten, dass diese Tests ohne ein Automatisierungstool nicht durchgeführt werden können.
- Jede Mutante wird anhand der gleichen Anzahl von Testfällen wie das Originalprogramm geprüft, daher muss eine große Anzahl von Mutanten gegen die gesamte Testsuite ausgeführt werden.
- Äquivalente Mutanten können durch keinen Test abgetötet werden, und ihre Trennung von echten Überlebenden erfordert in der Regel eine manuelle Überprüfung.
- Da die Methode den Quellcode verändert, ist sie nicht anwendbar auf Schwarz Box Tests.
Wann sollte man Mutationstests einsetzen?
Das oben beschriebene Kostenprofil bedeutet, dass Mutationstests selten bei jedem Commit über die gesamte Codebasis ausgeführt werden. Sie amortisieren sich dort, wo ein unentdeckter Fehler teuer ist und der zu testende Code klein genug ist, um sich schnell zu verändern.
- Sicherheitskritische oder finanzielle Logik — Zahlungsberechnung, Steuervorschriften und Autorisierungsprüfungen, bei denen eine unabsichtliche falsche Antwort schlimmer ist als ein Systemabsturz.
- Suiten mit verdächtig hoher Abdeckung — wenn die Abdeckung nahezu 100 Prozent beträgt, aber dennoch Fehler auftreten.
- Legacy-Code wird refaktoriert — Die Ergebnisse der Mutationsanalyse zeigen, ob die bestehenden Tests eine Regression aufdecken würden.
- Bibliotheken und gemeinsam genutzte Komponenten — ein Fehler in einem wiederverwendeten Komponente multipliziert sich mit jedem Anrufer.
- Teams üben Testgetriebene Entwicklung — Die Punktzahl überprüft, ob die zuerst geschriebenen Tests tatsächlich funktionieren.
Es lohnt sich in der Regel nicht, auf Wegwerfprototypen, auf dünnem Code oder generiertem Code ohne Verzweigungslogik oder auf Testsuiten, die von langsamen Prozessen dominiert werden, zu arbeiten. Integrationstests Das dauert schon Stunden für einen einzigen Durchlauf.
Die meisten Teams beschränken den Testlauf daher auf geänderte Dateien, legen einen Schwellenwert für die relevanten Module fest und überlassen den weiteren Testlauf dem größeren System. Regressionstests Die Suite trägt den Rest der Lebenszyklus von Softwaretests.



