Wie funktioniert Mutation Testing?

Was ist Mutation Testing?

Mutation Testing ist ein Softwaretest, wo künstliche Bugs (Mutationen) im Code produziert werden, um festzustellen, ob die vorhandenen Tests ausreichen, um diese künstlichen Fehler zu entdecken. Wenn ein zuvor erfolgreicher Test trotz absichtlich eingeführter Bugs weiterhin erfolgreich ist, weist dies auf mangelhafte Testgüte hin.

Wie stellen Sie tatsächlich die Qualität Ihrer Softwaretests fest? Erfahren Sie mehr darüber, warum Code Coverage nicht ausreicht, wie Mutation Testing funktioniert, welche Vorteile sich ergeben und welche Tools zur Verfügung stehen.

Ein vermeintlich gutes Qualitätsmerkmal für gute Software ist die Abdeckung mit Tests bzw. englisch: Coverage. Eine hohe Abdeckung der Produktiv-Codezeilen mit Tests (oder auch Überdeckung genannt) bedeutet weniger Bugs und Code der sich leicht bearbeiten lässt, Stichwort “Refactoring”. Dabei handelt es sich jedoch um eine Fehleinschätzung. Selbst eine Coverage von 100% gibt keine Aussagekraft über fehlerfreie Software und auch nicht über die Testgüte.

Warum reicht Code Coverage nicht aus?

Die Coverage ist ein Maß dafür, wie viele Zeilen an produktivem Code von automatisierten Tests ausgeführt werden. Wichtig dabei: Dazu reicht es, eine Methode in einem Test auszuführen und schon würde diese Methode “Coverage” haben, ohne auch nur eine einzelne Assertion im Test, also ohne dem Vergleich zwischen erwartetem und tatsächlichem Rückgabewert einer Methode.

Bekannt dazu ist die Anekdote über einen großen europäischen Konzern, der von seinen Offshore Dev-Teams 100% Testabdeckung gefordert hat. Diese haben daraufhin lediglich alle Methoden in der Test-Suite aufgerufen - ohne Assertion - und schon war 100% Testabdeckung mit fehlerfreien Tests erreicht. Der einzige Aspekt, den die Coverage also im Kontext des Testens berücksichtigt, ist welche Teile des Codes aufgerufen werden. Ob die Code-Teile auch fehlerfrei funktionieren, ist damit nicht garantiert.

Aber auch eine gute Test-Suite, die ausreichend Assertions beinhaltet, garantiert noch keine hohe Testgüte. Das Grundproblem dabei ist, dass automatisierte Tests noch keine Auskunft darüber geben, ob wirklich alle Ausführungspfade des Codes abgedeckt sind. Anders gesagt: Ein automatisierter Test prüft möglicherweise den “If” Teil einer Methode, aber nicht den “Else” Teil. Schlimmer noch: Wenn EntwicklerInnen bestehenden Code verändern, passieren möglicherweise Fehler, aus >= Abfragen werden beispielsweise irrtümlich > Abfragen. Ist ein entsprechender Test in der Lage diesen Fehler zu entdecken und “rot” oder bleibt der Test trotz dieses Bugs “grün”? Im ersten Fall ist eine entsprechend hohe Testgüte vorhanden, im zweiten Fall nicht.

Die Lösung - Mutation Testing

Das Prinzip, das sich dahinter versteckt, wurde schon vor einigen Jahrzehnten wissenschaftlich analysiert und vorgestellt (siehe: R. Lipton, “Fault Diagnosis of Computer Programs,” Student Report, Carnegie Mellon University, 1971).

Die Idee ist einfach: Software-Tests dienen dazu, Fehler im produktiven Code zu entdecken. Diese Fehler stammen meist aus der Hand der EntwicklerInnen, welche diese Fehler (meist unbewusst) implementieren. Ein Test, der zuvor grün war, sollte demnach rot werden, wenn er entsprechend hochwertig geschrieben ist, oder anders gesagt eine hohe Testgüte aufweist. Da es relativ zeitaufwendig und komplex ist, absichtliche Bugs zu produzieren, um die Testgüte von Software-Tests zu überprüfen, wird der Code in automatisierter Art und Weise künstlich verdreht und mit Bugs verändert. Der originale Code wird also “mutiert”.

Sobald diese Code-Mutationen automatisch erstellt wurden, wird die unveränderte Test-Suite erneut über den (jetzt mutierten) Code laufen gelassen. Die Grundannahme dabei: Wenn ein Test im Original-Code grün war, sollte er durch einen absichtlich produzierten Bug fehlschlagen und rot werden. Ist das nicht der Fall, bedeutet das, dass der Test nicht richtig testet, seine Testgüte also mangelhaft ist, oder es fehlen Tests, die ein entsprechendes Fehlverhalten abfangen können.

Das Springen von einem grünen zu einem roten Test in der Mutation ist in diesem Fall also gewollt. Man spricht auch davon, dass die Mutante getötet wurde (“killed”). Der andere Fall, dass der Test trotz absichtlich eingeführten Bugs grün bleibt, ist daher nicht gewollt. Man nennt dies eine überlebende Mutante (“survived”).

Welche Bugs werden eingeführt?

In der Java Welt ist PIT Mutation ein bewährtes Tool für automatisierte Mutation Coverage Analyse und ist für Maven und Gradle Umgebungen verfügbar. Im Build Prozess werden neue, vom originalen Source Code abgeleitete “Mutationen” erstellt. Dabei wird ein Set an vordefinierten Mutatoren (mutators) verwendet, die den originalen Code analysieren und in den mutierten Varianten beispielsweise statt “>=” Vergleichen “>” Vergleiche einsetzen. Ein anderes Beispiel ist, dass das Tool bei einem boolean Rückgabewert einfach den Rückgabewert der Methode invertiert.

Über die Maven oder Gradle Konfiguration können die Mutatoren beliebig konfiguriert werden. Eine genaue Übersicht der verfügbaren Mutatoren findet sich auf der Website des PIT Projektes: https://pitest.org/quickstart/mutators/

Vorteile und Nachteile von Mutation Testing

Mutation Testing hat einige Vorteile hinsichtlich der Qualitätsbeurteilung von Software. Der Qualitätsaspekt spiegelt sich in dem Fall in der wesentlich besseren Testgüte der Test-Suite wider. Der Einsatz von Mutation Testing zeigt folgende Grundsätze auf:

  • Mutation Testing testet nicht den Produktionscode, sondern die Test-Suite
  • Mutation Testing deckt primär fehlende Testabdeckung und Testqualität auf
  • Mutation Testing kann dabei helfen, unnötigen Code zu reduzieren
  • Das Aufspüren von Bugs ist nur ein sekundärer und beiläufiger Effekt von Mutation Testing

Die reine Testabdeckung (Coverage) sollte in modernem und hochwertigem Code jedenfalls nicht mehr als Maß für Qualität dienen. Mutation Coverage bietet dabei eine aussagekräftige Alternative und sollte heutzutage in keiner CI/CD Pipeline fehlen.

Jedoch gilt wie immer: kein Vorteil ohne Nachteile. Der Grundsatz in der testgetriebenen Softwareentwicklung, dass Tests schnell sein sollen, wird durch Mutation Testing ein wenig eingeschränkt. Die Generierung von Mutationscode und das Ausführen der gesamten Testsuite gegen jede einzelne Mutation erhöht die Testlaufzeit um ein Vielfaches. Das kann sich vor allem in einer großen Code-Base monolithischer Projekte auswirken.

Dennoch sollte Mutation Testing in keinem modernen Softwareprojekt ausgelassen werden, es lohnt sich.

Welche Mutation Testing Tools stehen zur Verfügung?

Im Java Universum bietet sich die Konfiguration mit Gradle/Maven, JaCoCo (als klassisches Coverage Tool) und PIT Mutation an.

Ähnliche Tools stehen auch für andere Programmiersprachen zur Verfügung:

Sparen Sie Kosten und Zeit durch eine ausführliche Testabdeckung!

Erfahren Sie mehr in unserem Blogbeitrag zum Thema Web Application Testing - vom Unit Test zum umfassenden Testkonzept für Web-Applikationen!

Jetzt mehr erfahren
Newsletter

Weitere interessante Artikel

Kontakt

Sie möchten sich unverbindlich über Ihr Softwareentwicklungs-Vorhaben austauschen? Erzählen Sie uns ein bisschen mehr!

Hannes Wambach,
VP Growth & Business
Development