Unit Tests sind doch weit weniger sinnvoll, als immer wieder behauptet. Es entsteht doch zusätzlicher Aufwand zur Implementierung, der Wartung von Unit Tests und die Infrastruktur muss auch erst geschaffen werden. Zudem weiß ich als guter Entwickler ohnehin, wo der Fehler auftritt. Mit guten Debugging-Skills kann ich jeden Fehler sofort finden und ausbessern. Hier eine kleine Auswertung aus der Praxis.
Rahmenbedingungen
Nachfolgend eine Architektur einer mittelgroßen Anwendung. Das User Interface wird – entsprechender einer Webanwendung – per HTML und JavaScript abgebildet. Die Daten werden über Services bezogen. Diese befragen wiederum einen Businesslogik-Layer. Die Kapselung der unterschiedlichen Datenquellen findet über Repositories statt. Die angebundenen Datenquellen sind unterschiedlicher Natur (DBMS, Sharepoint, etc.).

Die Testing-Infrastruktur
Eine häufige Ausrede findet sich in der Erstellung einer geeigneten Testing-Infrastruktur. Oftmals wird hier jedoch der falsche Weg eingeschlagen:
- Die Testing-Infrastruktur wird nicht zu Projektbeginn beim initialen Aufsetzen der Solution berücksichtigt. Erst zu einem späteren Zeitpunkt (vielfach nach zahlreichen Mannwochen Implementierung wird der Bedarf erkannt). Fragen bezgl. des Nachziehens von Tests, eventuell notwendigen Refactorings, um überhaupt ein Testing zu ermöglichen lassen den Aufwand nach oben treiben. Unit Tests werden nicht eingeführt, oder nur halbherzig.
- Aufsetzen der Unit Tests als Integrationstests. Services bedürfen oft einer Konfiguration (Verbindungseinstellungen, konfigurierte Provider etc.). Vielfach wird dies über Konfigurationsdateien vorgenommen, um am Zielsystem flexibel zu sein. Durch fehlendes Know-How bezgl. Mocking oder der schlichten Nichtverwendung entstehen komplexe Gebilde, die mit Unit Tests nichts zu tun haben und die Motivation, Tests zu schreiben aufgrund des Aufwandes erheblich senken.
Die Basis für Unit Tests muss dementsprechend also bereits zu Beginn eines Projektes berücksichtigt werden. Bei einer späteren Erweiterung müssen gegebenenfalls Refactorings in Kauf genommen werden, ebenfalls gilt es zu überlegen, welche Bereiche getestet werden sollen. Eine Beschränkung darauf als auch ein striktes Einhalten können die Situation wesentlich verbessern.
Was benötige ich für meine Testing-Infrastruktur?
Unabhängig aller im Web verfügbaren Diskussion und Über-Drüber-Lösungen benötige ich als Entwickler in der Realität wenig um erfolgreich Unit Testing zu betreiben:
- Visual Studio bietet bereits Testprojekte, welche den meisten Ansprüchen genügen werden. Natürlich gibt es hier zahlreiche Frameworks die verwendet werden können, das muss aber nicht sein. Das ergibt de facto keinen Aufwand. Der Wille als auch ein Basiswissen hinsichtlich Testing müssen vorhanden sein.
- Services, Provider und Co. beziehen sich meist auf eingebundene Ressourcen, die ein konfiguriertes System verlangen. Unit Tests verlangen nicht das Testen dieser Ressourcen, sondern lediglich der Funktionalität, die für den Aufruf durchlaufen werden müssen (bzw. der Businesslogik). Es bietet sich daher an, Services zu mocken. Dazu stehen zahlreiche Mocking-Frameworks (moq, Rhino Mocks etc.) zur Verfügung. Die Arbeitsweise unterscheidet sich kaum. Eine erste Einarbeitungsphase kann je nach Know How zwischen 30 und 120 Minuten abgeschlossen werden.
- Sinnvolle Basisklassen. Bestimmte Mocks bzw. Mocking-Konfigurationen werden für die meisten Tests verwendet. Gut überlegte Basisklassen erleichtern das tägliche Schreiben von Unit Tests ungemein. In der Regel entsteht hier jedoch meist laufender Aufwand durch die Erweiterung der Infrastruktur. Der initiale Aufwand beschränkt sich meist auf das Erkennen der ersten Anforderungen an die zu schreibenden Tests.
In der Regel empfiehlt es sich, mit Unit Tests zu beginnen und diese sukzessive zu erweitern. Das wirkt sich bei entsprechender Ernsthaftigkeit auf die gesamte Infrastruktur aus, womit sich diese quasi von alleine erweitert.
Die größte Hürde bei Unit Tests ist der innere Schweinehund. Ist dieser erst überwunden, schreiben sich die Unit Tests fast von alleine. Die zweite Hürde stellt sich durch die Frage nach den zu testenden Teilen der Software. Es ist wenig sinnvoll, alles testen zu wollen. Vielmehr sollte man sich auf wesentliche Bereiche der Software konzentrieren und die Stellen, welche die Basis der Anwendung ausmachen, gut zu testen.
Visual Studio bietet einem .NET Entwickler bereits viele Erleichterungen. Zusammen mit einem Mocking-Framework und einer Portion Willen können bereits gute Erfolge erzielt werden – und das ohne viel Aufwand.
Auswertung aus der Praxis
Den Aufwand für die Infrastruktur muss man als gegeben hinnehmen. Bei Bedarf kann dieser minimal gestaltet werden, was auch zielführend ist. Vielmehr zählt der laufende Aufwand zur Erstellung und Wartung von Unit Tests. Dieser ist in der Regel schwer zu beziffern. Nachfolgend jedoch eine durchgeführte Übersicht aus der Praxis, die sicherlich keine Antwort auf alle Projekte und Rahmenbedingungen darstellt, aber als guter Anhaltspunkt gesehen werden kann.
Es wurde festgestellt, dass pro QA-Durchlauf ca. 60 Bugs gefunden werden. Diese setzen sich aus UI-Bugs (unterschiedliche Browser, etc.), Fehler der Businesslogik und div. andere Fehler bei der Verarbeitung mit Fremdsystemen etc. zusammen. Je nach Bereich sind diese durch Unit Tests (Testing von JavaScript etc. wurde hier nicht berücksichtigt) feststellbar oder nicht (müssen also ohnehin manuell gefunden werden). Nachfolgend die entsprechende Liste.

Für die betroffenen Stellen waren in diesem Fall keine Unit Tests vorhanden. So mussten die gefundenen Fehler manuell geprüft, gefunden und gefixt werden. Im Zuge dessen (der Aufwand wurde extra erfasst) wurden Unit Tests für diese Fehler implementiert (siehe feststellbar durch Unit Tests). Dies dauerte in der Regel 10 Minuten. Da die Tests sinnvoller Weise während der Implementierung geschrieben werden und hier natürlich die zu testenden Fälle erst gefunden werden müssen (bzw. Tests für den Schön- als auch den Schlechtwetterfall zu implementieren sind), wurde das 4-fache der benötigte Zeit veranschlagt. Das Ergebnis ist in der nachfolgenden Übersicht zu sehen.

Das Ergebnis zeigt einen Unterschied von 5,7 Manntagen zugunsten der Unit Tests. Alle weiteren Fälle können durch Unit Tests (einige davon schon unter Betreibung höheren Aufwandes) nicht festgestellt werden und wurden auch nicht berücksichtigt.
Die Zahlen wurden im Zuge eines Sprints von 4 Wochen und einem Team von 3 Personen ermittelt. Eine Hochrechnung auf ein Entwicklungsjahr ergibt somit eine Differenz von fast 74 Manntagen, die anderweitig eingesetzt werden können, unter der Annahme, dass sich die Zusammenstellung ähnlich verhält (was jedoch in der Praxis nicht der Fall sein wird). Nichts desto trotz ergibt sich dadurch ein klarer Vorteil für den Einsatz von Unit Tests, da hier definitiv Aufwand eingespart wird – entgegen anderweitiger Meinungen.
Fazit
Dieser Berechnung liegt nur die Erfahrung aus einem einzigen Sprint einer Entwicklungsmannschaft zu Grunde und bedarf wohl die Erfassung weiterer Sprint, um das Ergebnis zu verfeinern. Es darf jedoch davon ausgegangen werden, dass mit zunehmender Projektgröße die Aufwandsersparnis steigt. Selbst in diesem Beispiel hätten fast 6 Manntage zielbringender eingesetzt werden. Statt Fehlersuche hätten weitere Funktionalitäten entwickelt, Dokumentationen geschrieben oder Anforderungen genauer hinterfragt werden können. Der Vollständigkeit halber muss erwähnt werden, dass auch das QA-Team Zeit für das Erfassen von Fehlern, der Schritte dahin etc. benötigt. Diese Zeit wurde nicht berücksichtigt …
An dieser Stelle würden mich Eure Erfahrungen hinsichtlich Motivation, Aufwände und Umgang mit Unit Tests in der Praxis interessieren. Wie läuft das in deinem Entwicklungsteam?