Wenn Sie sich ansehen, wie die meisten Programmierer ihre Zeit verbringen, so stellen Sie fest, dass Code zu schreiben nur ein kleiner Teil davon ist. Einige Zeit wird damit verbracht herauszufinden, was gemacht werden soll, einige Zeit wird auf das Design verwendet, aber die meiste Zeit wird mit der Fehlersuche ver- bracht. Ich bin sicher, dass jeder Leser sich an lange Stunden der Fehlersuche erin- nert, oft bis spọt in die Nacht hinein. Jeder Programmierer kann von Fehlern beichten, die zu beheben einen ganzen Tag (oder lọnger) dauerte. Den Fehler zu beheben geht meistens sehr schnell, aber ihn zu finden ist ein Albtraum. Und wenn Sie einen Fehler beheben, besteht immer die Mửglichkeit, dass ein weiterer auftreten wird und Sie dies nicht einmal bemerken, bevor es viel spọter ist. Sie ver- bringen dann eine Ewigkeit damit, diesen Fehler zu finden.
Das Ereignis, das mich auf den Weg selbst testenden Codes brachte, war ein Vor- trag auf der OOPSLA im Jahre 1992. Irgendjemand (ich meine, es war Dave Tho- mas) sagte nebenbei: ằKlassen sollten ihre eigenen Tests enthalten.ô Dies erschien mir als eine gute Art, Tests zu organisieren. Ich interpretierte diese Aussage so, dass jede Klasse eine eigene Methode (genannt test) haben soll, die benutzt wer- den kann, um sie zu testen.
Zu dieser Zeit beschọftigte ich mich auch mit inkrementeller Entwicklung, also versuchte ich den Klassen, bei denen ich ein Inkrement abgeschlossen hatte, Test- methoden hinzuzufügen. Das Projekt, an dem ich damals arbeitete, war ziemlich klein, so dass wir Inkremente ungefọhr jede Woche herausbrachten. Die Tests aus- zuführen war ziemlich einfach, aber obwohl die Tests leicht auszuführen waren, waren sie immer noch ziemlich nervend. Das lag daran, dass jeder Test Ausgaben
erzeugte, die auf der Konsole erschienen und die ich überprüfen musste. Ich bin nun aber ein ziemlich fauler Mensch und immer bereit, hart zu arbeiten, um Ar- beit zu vermeiden. Ich erkannte, dass ich, statt auf den Bildschirm zu starren, In- formationen aus dem Modell in eine Datei ausgeben und den Test dem Rechner überlassen konnte. Ich brauchte nur das erwartete Ergebnis in den Testcode zu schreiben und einen Vergleich zu machen. So konnte ich die Testmethode jeder Klasse ausfỹhren, und diese wỹrde nur ằOKô auf den Bildschirm schreiben, wenn alles in Ordnung war. Die Klasse war nun selbst testend.
Nun war es leicht, einen Test durchzuführen – so einfach wie umzuwandeln. So begann ich die Tests jedes Mal auszuführen, wenn ich den Code umwandelte.
Sehr bald bemerkte ich, dass meine Produktivitọt nach oben schoss. Ich stellte fest, dass ich weniger Zeit mit der Fehlersuche verbrachte. Wenn ich einen Fehler einbaute, der in einem früheren Test aufgefallen war, so würde er auffallen, sobald ich diesen Test ausführte. Da der Test vorher funktioniert hatte, wusste ich, dass der Fehler in der Arbeit steckte, die ich seit dem letzten Test gemacht hatte. Da ich die Tests họufig ausfỹhrte, waren nur wenige Minuten vergangen. Ich wusste da- her, dass der Fehler in der Arbeit steckte, die ich seit dem letzten Test erledigt hatte. Da dieser Code mir noch prọsent war und es sich nur um wenig Code han- delte, war der Fehler leicht zu finden. Fehler, die früher eine Stunde oder mehr Suchzeit erforderten, konnte ich nun in wenigen Minuten finden. Ich hatte nicht nur selbst testende Klassen geschaffen, sondern dadurch, dass ich die Tests oft ausfỹhrte, hatte ich auch einen leistungsfọhigen Fehlerdetektor.
Als ich dies bemerkte, wurde ich aggressiver, was die Ausführung von Tests an- ging. Anstatt auf das Ende eines Inkrements zu warten, würde ich die Tests nach jedem Einfügen einer kleinen Funktion ausführen. Ich würde jeden Tag etwas Neues und die Tests, um es zu testen, hinzufügen. Heute verwende ich kaum mehr als einige Minuten auf die Fehlersuche.
Natürlich ist es nicht einfach, andere zu überzeugen, diesem Weg zu folgen. Tests zu schreiben heiòt sehr viel zusọtzlichen Code zu schreiben. Solange Sie es noch nicht am eigenen Leibe erfahren haben, wie dies die Programmierung beschleu- nigt, scheint Selbsttesten keinen Sinn zu machen. Dies wird nicht dadurch einfa- Stellen Sie sicher, dass alle Tests vollstọndig automatisiert werden und dass sie ihre Ergebnisse selbst überprüfen.
Eine Testsuite ist ein leistungsfọhiger Fehlerdetektor, der die Zeit fỹr die Fehler- suche dramatisch reduziert.
cher, dass viele Programmierer nie gelernt haben, Tests zu schreiben oder auch nur an Testen zu denken. Werden Tests manuell ausgeführt, so sind sie eine ma- genverstimmende Unanehmlichkeit. Sind sie automatisiert, so kann das Schrei- ben von Tests sogar Spaò machen.
Am nützlichsten ist es, Tests zu schreiben, wenn Sie beginnen, ein Programm zu schreiben. Wenn Sie etwas hinzufügen wollen, schreiben als erstes einen Test. Das ist nicht so abwegig, wie es sich vielleicht anhửrt. Wọhrend Sie den Test schrei- ben, fragen Sie sich, was Sie tun müssen, um die neue Funktion einzufügen. Den Test zu schreiben, führt dazu, dass Sie sich auf die Schnittstelle konzentrieren, an- statt auf die Implementierung. Dies ist immer empfehlenswert. Es gibt Ihnen auch ein eindeutiges Kriterium, wann der Code fertig ist: wenn der Test funktio- niert.
Die Idee des họufigen Testens ist ein wichtiger Teil des extremen Programmierens [Beck, XP]. Der Name beschwửrt die Vorstellung von Programmierern als schnelle, bewegliche Hacker herauf. Aber extreme Programmierer sind hinge- bungsvolle Tester. Sie wollen Software so schnell wie mửglich entwickeln, und sie wissen, dass Tests ihnen helfen, so schnell voranzukommen, wie sie kửnnen.
Das reicht an Polemik. Obwohl ich davon überzeugt bin, dass jeder vom Schrei- ben selbst testenden Codes profitiert, ist dies nicht das Thema dieses Buches. Die- ses Buch handelt vom Refaktorisieren. Das Refaktorisieren erfordert Tests. Wollen Sie refaktorisieren, so müssen Sie Tests schreiben. Dieses Kapitel zeigt Ihnen, wie Sie damit in Java beginnen. Dies ist kein Buch über das Testen, ich gehe also nicht allzu sehr ins Detail. Aber ich habe festgestellt, dass bereits wenige Tests einen ỹberraschend groòen Nutzen bringen kửnnen.
Wie auch alles andere in diesem Buch, beschreibe ich den Ansatz des Testens mit Beispielen. Wenn ich Code entwickle, schreibe ich gleichzeitig die Tests. Aber oft, wenn ich mit anderen refaktorisiere, haben wir es mit nicht selbst testendem Code zu tun. Deshalb machen wir den Code zunọchst selbst testend, bevor wir re- faktorisieren.
Das Standardidiom in Java für Tests ist die testende main-Funktion. Die Idee ist, dass jede Klasse eine main-Funktion haben sollte, die die Klasse testet. Das ist eine vernünftige Konvention (wenn auch wenig beachtet), aber sie kann mühselig werden. Das Problem einer solchen Konvention besteht darin, dass es schwierig ist, viele Tests leicht auszuführen. Ein anderer Ansatz besteht darin, separate Test- klassen zu entwickeln, die in einem Framework zusammenarbeiten, um das Tes- ten einfacher zu machen.