Ein Experiment zu 100% Testabdeckung
Wer achtet auf bei seinen Unit-Tests auf die Testabdeckung? Was ist mit nicht getesteten Zeilen, sind die überflüssig? Ich werde über ein Experiment berichten: Ist es möglich, 100% Testabdeckung zu erreichen? Sind Änderungen am Code dafür notwendig? Wie ändert sich dadurch der eigene Programmierstil?
'System under Test' war der Interpreter einer funktionalen Sprache (Sprachkern und zugehörige Standardbibliothek). Beim Test der I/O Funktionen auf Datei- und HTTP-Basis habe ich den Bereich der Unit-Tests in Richtung Integrationstests verlassen. Spoiler: Auch das lässt sich automatisieren und zu 100% abdecken.
Zielgruppe: Tester*innen, Entwickler*innen
Voraussetzung: Java-Kenntnisse, Neugier, Zweifel
Level: select
Extended Abstract:
Im Rahmen eines Hobby-Projekts habe ich in Java einen Interpreter für eine Lisp-ähnliche funktionale Sprache entwickelt: FPL (functional programming language, siehe: https://github.com/rbutenuth/fpl).
Wer Lisp sagt, muss auch Listen implementieren, und zwar immutable bzw. persistent. Die Implementierung der zugehörigen Datenstruktur ist recht komplex geraten, so dass ich sie gründlich testen wollte. Als die Testabdeckung schon recht hoch war, bin ich auch noch die letzte Meile bis zu 100% gegangen, was bei einer Klasse mit wenigen Abhängigkeiten noch einfach war.
Jetzt aber war mein Ehrgeiz geweckt: Ist das für das gesamte Projekt möglich? Für den Interpreterkern und die puren Funktionen (keine Seiteneffekte) war es noch einfach. Schwieriger wurde es bei der Standardbibliothek, die Dateioperationen, einen Web-Server und einen Web-Client enthält. Aber auch dort waren irgendwann die 100% erreicht, auch wenn dazu teilweise der Code geändert werden musste (typischerweise zum Besseren). Man glaubt auch nicht, wie viele Fehler (auch einen recht gruseligen) man dabei noch findet.
Aber selbst 100% garantieren keine Fehlerfreiheit: Als ich beim Advent of Code (siehe https://adventofcode.com/2021/) die Aufgaben in FPL gelöst habe, tauchte in der Listenimplementierung doch noch ein Fehler auf. (meine unvollständigen Lösungen aus dem Jahr 2021: https://github.com/rbutenuth/advent-of-code).
Sollte man immer so programmieren und testen? Im Endergebnis sind Code und Test in diesem Beispiel ähnlich umfangreich, es steckt also viel Aufwand in den Tests. Auf der anderen Seite: Wer glaubt, dass eine Zeile Code korrekt ist, die nie im Test ausgeführt wurde?
Senior Integration Architect
Dr. Roger Butenuth arbeitet seit 2012 bei der codecentric AG mit den Schwerpunkten Integration und Architektur.
Weiterhin interessieren ihn Themen rund um Performance, Parallelität.
