Mutationstests mit PIT in Java
Unit-Tests gehören bei vielen Entwicklern zur täglichen Arbeit als Schutz vor Regressionen und als lebende Dokumentation. Aber wie lässt sich die Qualität der Tests überprüfen?
![Mutationstests mit PIT in Java](https://heise.cloudimg.io/width/610/q85.png-lossy-85.webp-lossy-85.foil1/_www-heise-de_/imgs/18/2/3/1/6/4/9/3/teste-22a07b93c6736072.jpeg)
- Johannes Dienst
Softwareentwicklung ohne Tests auf allen Ebenen ist heutzutage nicht mehr vorstellbar. Besonders die testgetriebene Entwicklung führt zu leicht testbarem Code. Den Mehraufwand für das Schreiben der Tests sparen Teams bei Refactorings wieder ein. Außerdem garantiert eine ausreichend große Testsuite den Schutz vor Regressionen.
Demnach stellt sich die Frage, wer die Qualität der Tests überprüft und sicherstellt, dass sie sinnvoll sind und tatsächlich Fehler aufdecken. Als klassische Methoden bieten sich die Paarprogrammierung oder Code Reviews an. Diese Methoden sind effizient, hängen jedoch von der Kompetenz der Entwickler ab. Schöner wäre es, eine automatisierte Überprüfung der eigenen Testsuite durchführen zu können.
Überdeckungsmaße
Eine Testsuite, die effektiv Regressionen und Abweichungen von der Spezifikation entdecken soll, muss eine hohe Qualität aufweisen. Der Qualitätsbegriff ist dabei schwammig, da er meistens subjektiv ist und nicht auf Fakten beruht.
Codeüberdeckungsmaßen sollen die Effizienz einer Testsuite quantifizierbar machen und so die Qualität der Tests sicherstellen. In der einfachsten Variante testen sie, ob die Testsuite eine bestimmte Codezeile ausführt. Das Ergebnis ist eine Prozentangabe des von Tests ausgeführten Codes. Ob eine Prozentzahl als Qualitätsmaßstab geeignet ist, sei dahingestellt.
Darüber hinaus gibt es besser ausgefeilte Varianten der Codeüberdeckung. Unter anderem kann die Zweigüberdeckung messen, ob jeder Ausführungszweig der Codebasis mindestens einmal durchschritten wurde, was eine härtere Anforderung an die Testsuite stellt.
Schließlich gibt es noch die Bedingungsüberdeckung mit ihren populären Varianten MC/DC und MCC. Sie sind im Rahmen der Zertifizierungen DO-178B und DO-178C für Software der kritischsten Ebene gefordert und haben eine äußerst umfangreiche Testsuite zur Folge.
Überdeckung alleine ist unzureichend
Überdeckungsmaße sind eine nützliche Angelegenheit, um blinde Flecken in der eigenen Testsuite zu erkennen. Auch marketingtechnisch ist eine hundertprozentige Überdeckung des Codes eine wirksame Aussage. Man kann sich sicher fühlen, dass die Tests das tun, was sie sollen: jede Zeile Code ausführen.
In Wahrheit ist eine hundertprozentige Codeüberdeckung aber kein Garant für Fehlerfreiheit. Vielmehr ist sie als Hinweis auf eine gewisse Sorgfalt beim Erstellen der Tests zu sehen. Mit hoher Wahrscheinlichkeit ist die Testsuite in der Lage, Regressionen zu finden. Die Prozentzahl der abgedeckten Regressionen bleibt jedoch im Dunkeln.
Die Qualität der Tests hängt von den verwendeten Assertions ab. Sind diese unzureichend formuliert, nützt die vollständige Überdeckung nichts. Als Beispiel sei die folgende Assertion aus einem JUnit-Testfall gegeben, bei der die Beschaffenheit eines von einer Methode zurückgegebenen Objekts Ziel des Tests ist:
@Test public void getActiveObjectFromDatabase {
Object o = database.getActiveObject(42);
assertNotNull(o);
}
Der Testfall ist sinnvoll, da die Methode nicht null zurückgeben soll. Ist die Methode einfach gehalten, kann er schon ausreichen, eine Zeilenüberdeckung von 100 % herzustellen. Wenn er jedoch der einzige Testfall für die Methode ist, hat die Testsuite einen blinden Fleck. Unter anderem fehlt eine Prüfung darauf, ob das Objekt den Vorstellungen entspricht, die es erfüllen soll.
Beim Betrachten der Methode werden dem Objekt noch Zusatzinformationen mitgegeben, die der Test nicht überprüft:
public Object getActiveObject(int i) {
Object o = this.retrieveObject(i);
o.setState("active");
o.setDirty(true);
return 0;
}
Der Test deckt nicht auf, ob die Zuweisungen verschwinden oder sich ändern. Eine Regression ist somit unbemerkt in die Codebasis gewandert.
Robert C. Martin hat den Umstand treffend ausgedrückt: "Nimm alle Assertions aus deinen Tests, und deine Überdeckung bleibt unverändert!" (freie Übersetzung aus dem Blog)