Mutationstests können bei Schulungen oder kleineren Projekten mit begrenzten Teilnehmern und ohne Zeitvorgaben nützlich sein, aber sie sind im Allgemeinen komplizierter als das Umdrehen eines einzelnen Bits und die Analyse der Ergebnisse einer Teilmenge von Tests.
Außerdem ist es eine falsche Annahme, dass ein (menschliches oder automatisiertes) Orakel alle Fehler erkennt. Automatisierte Orakel können nur Probleme erkennen, für die sie programmiert sind.
Mutationstests sind (nach meiner Erfahrung) nützlich, wenn sie auf folgende Weise durchgeführt werden:
- Von Beginn eines kleinen/mittleren Projekts an.
In diesem Szenario unterstützen Mutationstests bei der Entwicklung. Ihr könnt realistischerweise ein hohes Mutationsergebnis anstreben.
Mutationstests werden Lücken in eurer Testsuite aufzeigen (Beispiele, die ich immer wieder sehe, sind interaktionsorientierte Tests, die nicht überprüfen, ob Methoden tatsächlich den Wert zurückgeben, den sie berechnen sollen, ungeprüfte Grenzen und viele Fälle, in denen der TDD-Prozess, den ihr angeblich befolgt, eindeutig nicht eingehalten wurde, da ihr Methodenaufrufe herausnehmen könnt, ohne dass ein Test fehlschlägt).
Eine überlebende Mutation führt dazu, dass Sie eines von drei Dingen tun
- Schreiben eines neuen Tests
- Löschen von Code
- Umschreiben von Code
- Häufig ist das Ergebnis 2) oder 3).
2) ist selbsterklärend - Ihr habt einen nutzlosen Code, der entfernt werden kann, 3) ist weniger offensichtlich und bezieht sich auf gleichwertige Mutationen. Ich habe festgestellt, dass Code, der zu einer gleichwertigen Mutation mutiert werden kann, oft besser durch Code ausgedrückt werden kann, der nicht zu einer gleichwertigen Mutation mutiert werden kann. Das Ergebnis ist in der Regel einfacher zu verstehen und zu pflegen.
Einige äquivalente Mutationen werden jedoch immer bestehen bleiben - in der Regel sind diese auf Leistungsprobleme innerhalb des Codes zurückzuführen.
Die Definition, was ein kleines/mittleres Projekt ausmacht, ist etwas schwierig festzulegen - aber im Grunde genommen ist es klein genug, dass die Analyse in einer Zeit abgeschlossen wird, die niedrig genug ist, um als Teil Ihrer Kodierungs-Feedbackschleife akzeptabel zu sein. Glücklicherweise haben die Werkzeuge für Mutationstests ihre Leistung in den letzten Jahren um ein Vielfaches verbessert. (siehe http://pitest.org/java_mutation_testing_systems/ für eine Diskussion über das Warum/Wie).
Mutationstests wurden in einigen kleinen Systemen eingesetzt, z. B.: siehe Artikel "An intuitive approach to determine test adequacy in safety-critical software". Hier ist die Zusammenfassung:
Für sicherheitskritische Software müssen strenge Qualitätsstandards eingehalten werden, und es wird erwartet, dass sie gründlich getestet wird. Ausführliche Tests von Software sind jedoch in der Regel nicht praktikabel. Die beiden größten Herausforderungen für ein Softwaretestteam sind die Erstellung effektiver Testfälle und der Nachweis der Angemessenheit der Tests.
In diesem Papier wird ein intuitiver und konservativer Ansatz zur Bestimmung der Testadäquanz bei sicherheitskritischer Software vorgeschlagen. Der Ansatz wird anhand einer Fallstudie demonstriert: dem Kerntemperaturüberwachungssystem eines Kernreaktors. Wir kombinieren die konservative Testabdeckung von Testfällen mit eindeutigem Ausführungspfad und die Ergebnisse von Mutationstests, um die Testadäquanz zu bestimmen.
Obwohl Mutationstests eine leistungsstarke Technik sind, hat die Schwierigkeit, gleichwertige Mutanten zu identifizieren, ihren praktischen Nutzen eingeschränkt. Um Vertrauen in die berechnete Testadäquanz zu gewinnen:
müssen Fehler beim Mutationstest auf allen möglichen Ausführungspfaden des Codes induziert werden,
müssen die Eigenschaften der nicht getöteten Mutanten untersucht werden, und
alle gleichwertigen Mutanten müssen entdeckt werden.
Diesbezüglich;werden die Ergebnisse der statischen, dynamischen und Überdeckungsanalyse der Mutanten vorgestellt, und
eine Technik zur Identifizierung der wahrscheinlichen äquivalenten Mutanten wird vorgeschlagen.
Das Gleiche wie oben, aber die Analyse ist auf neuen Code beschränkt. Sie kann sowohl während der Entwicklung als auch im Rahmen von Pair-Reviews usw. nützlich sein. Sie findet Lücken in der Testsuite, kann aber auch nützliche Diskussionen über den Code auslösen.
In diesem Szenario wird ein Teil einer Codebasis von Interesse für die Analyse ausgewählt - oft zur Unterstützung eines Refactorings.
Wie zuvor könnt ihr Tests hinzufügen, aber ihr würdet euch wahrscheinlich nicht die Mühe machen, Code zu löschen oder neu zu schreiben, da er wahrscheinlich ohnehin ersetzt wird. Sobald alle überlebenden Mutationen untersucht worden sind, haben ihr jedoch ein genaues Verständnis für das mit dem Refactoring verbundene Risiko gewonnen.
Die meisten Leute scheinen davon auszugehen, dass Mutationstests verwendet werden sollten.
Ich habe dies noch nie versucht und würde nicht erwarten, dass es einen großen Nutzen bringt.
Bei einer großen Codebasis sind die Analysezeiten lang, und die Anzahl der überlebenden Mutationen ist wahrscheinlich hoch. Der Versuch, jede einzelne zu bewerten, wäre sehr zeitaufwändig (javalanche soll in diesem Bereich eine gewisse Hilfe bieten - ich habe es jedoch nicht selbst ausprobiert und gehe davon aus, dass es mit hohen Leistungskosten verbunden ist).
Mutationstests könnten vielleicht noch zur Bewertung der Gesamtqualität einer bestehenden Suite verwendet werden. Man könnte eine Zufallsstichprobe von überlebenden Mutationen nehmen und jede davon auf ihre Äquivalenz hin überprüfen - dies könnte dann dazu verwendet werden, die wahrscheinliche Anzahl der überlebenden Mutationen zu bestimmen, die für Mängel in der Testsuite stehen. Dies habe ich jedoch nicht selbst ausprobiert.
Neueste Kommentare