Testautomatisierung in Legacy-Systemen
Seite 2: Greenfield/Brownfield
Auf der grĂĽnen Wiese
Bei neuen Projekten, die auf der grĂĽnen Wiese beginnen, ist es relativ einfach, gute Tests aufzusetzen. Solche Greenfield-Systeme haben meist eine moderne Architektur, etwa in Form sauber getrennter Schichten:
Hier können alle gängigen Arten von Tests Verwendung finden, beispielsweise:
- Unit-Tests überprüfen einzelne Module der Software, zum Beispiel Klassen (Units) der Geschäftslogik-Schicht. Weist die getestete Klasse Abhängigkeiten zu anderen Klassen auf, werden diese im Test "weggemockt", das heißt durch Dummys ersetzt. So lässt sich die Klasse isolieren und ohne Nebeneffekte testen. Sind die Tests in der Sprache der Anwendungsdomäne geschrieben, dokumentieren sie zudem das Verhalten der Anwendung in lesbarer Form:
- Integrationstests überprüfen das Zusammenspiel mehrerer Module, auch über mehrere Schichten hinweg. Zum Beispiel könnte ein Integrationstest einen bestimmten Datenbestand in die Datenbank einspielen, dann eine Methode der Geschäftslogik-Schicht aufrufen (ohne die Abhängigkeit zur Datenbank wegzumocken) und schließlich das Ergebnis prüfen. So wird neben der Geschäftslogik das Zusammenspiel mit der Datenbank getestet.
- GUI-Tests für Anwendungen mit grafischer Benutzeroberfläche sind eine spezielle Form der Integrationstests – sie testen die Software, indem sie die GUI bedienen, also zum Beispiel Buttons anklicken und Anzeigetexte in Dialogen überprüfen.
Es gibt eine Reihe weiterer Arten von Tests, die hier aber nicht berĂĽcksichtigt werden.
Bei Greenfield-Systemen lassen sich prinzipiell alle Arten von Tests einsetzen. Empfohlen wird im Allgemeinen ein Mix aus vielen Unit-Tests mit einigen Integrationstests. GUI-Tests werden eher selten eingesetzt, weil sie aufwendig zu warten sind und langsam laufen. Wenn sie ĂĽberhaupt zur Anwendung kommen, dann meist in geringem Umfang:
Im Matsch des Brownfields
Bei historisch gewachsenen Altsystemen (Brownfield-Software) ist die Situation weniger komfortabel. Solche Legacy-Systeme weisen häufig statt einer Schichtenarchitektur mit kleinen Klassen eine monolithische Struktur auf. Zudem haben sie oft keine oder fast keine automatischen Tests. Wenn eine solche Anwendung geändert werden soll, steht man vor massiven Problemen. Oft stellt sich heraus, dass für die Implementierung der gewünschten Änderung ein Umbau des Codes notwendig ist. Ein Umbau birgt aber die Gefahr, Fehler an anderer Stelle nach sich zu ziehen. Da automatische Tests fehlen, sind die Nebeneffekte der Veränderung nur mühsam durch manuelle Tests herauszufinden.
Wer also zuerst Unit-Tests einführt, um eine Absicherung für künftige Änderungen zu haben, stellt oft fest, dass die Software aufgrund ihrer Architektur nicht Unit-testbar ist. Sie bräuchte zunächst ein Refactoring. Das lässt sich aber, wie schon festgestellt, ohne Tests eigentlich nicht wagen.
Eine solche Legacy-Software soll hier als Beispiel dienen. Es handelte sich um eine monolithische VB6-Anwendung, die halbautomatisch nach .NET migriert wurde und dort weiterentwickelt werden sollte. Es gab keinerlei automatische Tests. Die Anwendung besaß keinerlei Schichtenstruktur, ein Großteil der Geschäftslogik befand sich in Form von SQL-Statements in den Oberflächenelementen wie Formularen und Berichten. Einige Teile der Anwendung wurden vermutlich gar nicht mehr verwendet – es war aber nicht bekannt, welche das waren.