Hallo Spaß-Coder,
habt ihr auch schon mal eine Änderung an eurem Code vorgenommen, alles geprüft und hinterher stellte sich doch heraus, dass noch ein Fehler drin war? War dieser Fehler vielleicht in der Vergangenheit bereits einmal aufgetreten und ist nun wieder passiert? Oder seid ihr einmal in der Situation gewesen eine Anwendung zu prüfen und habt euch darüber geärgert, dass ihr bei jeder Änderung wieder von Vorne anfangen müsst?
In solchen Fällen hilft es uns, unsere Tests zu automatisieren.
Warum Testautomatisierung?
Stellt euch vor, wir sollen am unten abgebildeten System eine Änderung vornehmen. Das Verhalten soll sich also ändern, wenn an dem 4. grünen Drehregler der 5. Reihe von rechts gedreht wird. Wo liegt nun das Problem?
Nun, wir müssen nun im Grunde jede Kombination der Drehregler prüfen. Unser geänderter Drehregler ganz links, Mittelstellung und ganz rechts prüft zunächst, ob unsere gerade implementierte Änderung das gewünschte Verhalten aufweist. Aber wie stellen wir sicher, das unser geänderter Drehregler auch dann noch funktioniert, wenn wir den schwarzen Drehregler hinten rechts nach ganz links drehen? Oder der zweite Schalter in der vorderen ersten Reihe gedrückt ist…oder nicht gedrückt ist?
Wer von euch hat Lust, all diese Kombinationen manuell zu überprüfen? Keiner? Das überrascht uns nicht.
Schaut euch mal das Bild an. Nun denkt an euer aktuelles Software-Projekt. Ist euer Software-Projekt wesentlich weniger Komplex als das abgebildete System? Habt ihr nicht auch ganz verschiedene Kombinationsmöglichkeiten von Einstellungen, bei denen ihr nicht abschätzen könne, welche Auswirkungen sie auf den Rest eures Systems haben?
Wenn wir also ein solches System haben, bei dem wir bei jeder Änderung immer wieder unzählige Kombinationen testen und prüfen müssen, wie würden wir uns wünschen, wie das abläuft?
Vielleicht so:
Nach einer Änderung an unserem System drücken wir auf einen Knopf und ab geht die Wilde Fahrt. Das System läuft los und testet sich selbst und das immer und immer wieder. Sobald wir auf den Knopf drücken, testet sich das System und wir erhalten unmittelbar eine Rückmeldung darüber, ob das System noch funktioniert oder nicht.
Noch besser wäre für unsere Software-Systeme, dass sie sich automatisch prüfen, wir also nicht einmal mehr auf den Knopf drücken müssen. Aber das ist für uns Software-Entwickler ja die leichteste Übung. Bei dem abgebildeten System ist das Vorgehen vielleicht nicht die beste aller Ideen 😉
Machen wir noch ein anderes Beispiel. Nehmen wir an, wir haben das unten abgebildete System für einen unserer Kunden entwickelt. Es funktioniert seit ein paar Monaten. Durch eine neue Attraktion in der Nähe hat sich aber das Verkehrsaufkommen geändert und in einer der von unserem System gesteuerten Zufahrtsstraßen kommt es seit ein paar Tagen immer wieder zu Staus. Unser Kunde möchte nun, dass wir die Steuerung so ändern, dass die Staus nicht mehr vorkommen.
Was machen wir also? Wir ermitteln die Ursache für die Staus und verändern das Verhalten unseres Systems so, dass diese in Zukunft nicht mehr vorkommen. Aber was nun? Können wir mit Gewissheit sagen, dass unsere Änderung nicht Staus an anderen Stellen des Systems verursacht? Können wir sicherstellen, dass das System als Ganzes noch funktioniert?
Der Kunde möchte schnell eine Lösung haben. Aber wenn wir unsere Änderung durchgeführt haben und das neue Verhalten an unsere Kunden ausliefern, darf es auf gar keinen Fall so enden:
Wir müssen sicherstellen, dass das System weiterhin genauso funktioniert wie vorher, aber das geänderte Verhalten für die eine Zufahrtsstraße aufweist. Wir wollen aber – genauso wie im obigen Beispiel – nicht alle Kombinationen des Systems manuell prüfen. Auch wäre es nicht im Sinne unseres Kunden, wenn wir die Änderung erst einmal wochenlang einem manuellen Test unterziehen, bevor er die Änderung bekommt. Bis dahin werden viele Autofahrer verärgert sein, vielleicht wird es sogar Verkehrsunfälle geben. Es ist also wichtig, dass unsere Änderung schnell zum Kunden kommt. So stellen wir den Kunden zufrieden und erhöhen damit auch die Wirtschaftlichkeit unserer Leistung.
Mit unseren Software-Systemen ist das genauso. Der Kunde möchte ein geändertes Verhalten. Wir implementieren es und müssen sicherstellen, dass
- unsere Änderung so funktioniert, wie der Kunde sich das vorstellt
- unsere Änderung an einem Teil des Systems nicht andere Teile negativ beeinflusst
- wir unsere Änderung wirtschaftlich profitabel umsetzen und prüfen
Arten der Testautomatisierung
Es gibt verschiedene Arten von Tests, auf die wir in folgenden Artikeln noch weiter eingehen werden hier zunächst eine kurze Übersicht, was euch zum Thema noch erwartet:
- UI-Test
Im UI-Test wird unsere Anwendung auf Basis der Benutzer-Oberfläche, also aus Sicht des Anwenders, geprüft. UI-Tests stellen die höchste Ebene des Tests dar. Es wird die Anwendung als ganzes getestet, nicht einzelne Teile daraus. Einen UI-Test führt auch der Anwender aus, wenn er überprüft, ob unsere erstellte Anwendung seinen Anforderungen genügt.. - Regressionstest
Im Regressionstest prüfen wir, dass es in einer neuen Version unserer Software keine unerwünschten Änderungen gibt. Dazu werden die Ergebnisse der Software vor unserer Änderung mit den Ergebnissen der Software nach der Änderung verglichen. Diese Tests prüfen typischerweise nicht die Oberfläche, sondern die in der darunterliegenden Schicht befindlichen Funktionen und Services. Der Begriff wird oft auch als als Synonym für „wiederholbare automatisierte Tests“ verwendet. - Integrationtest
In einem Integrationstest prüfen wir, ob mehrere Komponenten unseres Softwaresystems zusammenpassen. Ob also z.B. unsere Datenbankzugriffe auch dann noch funktionieren, wenn sie über einen Service angesprochen werden, oder verschiedene Datenbankanfragen hintereinander das gleiche Ergebnis liefern, wie die einzeln getesteten Anfragen. - Unit-Test
Bei einem Unit-Test werden einzelne Komponenten unseres Softwaresystems geprüft. Eine Einheit (engl. Unit) kann dabei eine Klasse oder eine Funktion sein.
Diese Testarten bauen aufeinander auf. Von unten (Unit-Test) nach oben (UI-Test) prüfen sie immer allgemeinere Teile unserer Anwendung. Unsere Klassen und Funktionen (Methoden) werden in einzelnen Unit-Tests geprüft. Ein System vereint in aller Regel bereits mehrere Komponenten und kann somit nur in einem Integrationstest sinnvoll getestet werden. Das Zusammenspiel dieser Systeme wird dann durch unsere Regressionstests überprüft und ob das Ganze für den Anwender die gewünschte Wirkung hat, prüfen unsere UI-Tests.
Alle Ebenen sind gleich wichtig, da sie aber aufeinander aufbauen, sollte beim Test mit den unteren Ebenen begonnen werden. Beim BDD – dem Behavior Driven Development – fangen wir in der Regel oben in der Kette an, aber darauf kommen wir zu einem späteren Zeitpunkt nochmal zu sprechen.
Was spricht für Testautomatisierung?
Zusammenfassend noch einmal kurz, was dafür spricht, unsere Tests zu automatisieren.
- Wiederholbarkeit
- klare Erwartungen
- leicht überprüfbar
- schnelles Feedback
- Aufdecken unerwünschter Side-Effects an der Software
- nachhaltige Wirtschaftlichkeit bei der Entwicklung
Aus den oben genannten Beispielen sollten hervorgehen, warum wir diese Aspekte mit Testautomatisierung erreichen.
Was spricht gegen Testautomatisierung?
Wie bei allem gibt es auch bei der Testautomatisierung Nachteile. Es sind:
- Kosten
- Wartung des Test-Codes
- Know-How-Aufbau
Wenn wir nun zusätzlich zu unserem Produktionscode nun auch immer Tests schreiben, werden wir mehr Zeit brauchen, um ein neues Feature zu entwickeln. Es wird also teurer.
Genauso sieht es aus, wenn wir das Verhalten unserer Software ändern. Soll ein Fenster nun keinen roten Rahmen mehr haben, sondern einen blauen, unser Test aber auf einen blauen Rahmen prüft, müssen wir nicht nur die Farbe des Rahmens ändern, sondern auch den Test, da der ja bisher auf einen roten Rahmen geprüft hat. Auch hier wird das Ändern eines Verhaltens teurer, da wir nicht nur das Verhalten, sondern auch den Test-Code anpassen müssen.
Zum Schluss müssen wir auch Know-How zum Thema Test-Automatisierung aufbauen. Wir müssen und mit Werkzeugen beschäftigen, für uns klar machen, wie wir damit arbeiten möchten, Test-Methodiken lernen und entwickeln… auch das kostet Zeit.
Unterm Strich kann man alle Nachteile auf einen Punkt reduzieren: Kosten. Wir sehen diese Kosten aber weniger als Kosten, sondern vielmehr als Investition. Wir investieren in Know-How und die Erstellung automatisierter Tests, um die oben aufgelisteten Vorteile erreichen zu können.
Unsere Erfahrung mit Testautomatisierung
Seit einigen Jahren setzen wir in unseren Pair-Programming-Sessions auf Unit-Tests. Auch Integrationstests schreiben wir oft, vor allem, wenn wir Test-Driven (zuerst der Test, dann erst der Produktionscode) vorgehen (was wir nicht immer machen). Es ist einfach ein gutes Gefühl, wenn wir eine Klasse oder ein Modul refaktorisieren, dass wir sicher sein können, dass es hinterher auch noch genau das macht, was es soll. Oder wenn wir ein neues Feature hinzufügen, sicher sind, dass alle anderen Features noch funktionieren. Es gibt uns Sicherheit und macht uns mutiger, auch mal größere Änderungen durchzuführen.
In unserem beruflichen Kontext arbeiten wir mit sehr komplexen Software-Systemen und vermissen dort an vielen Stellen eine durchgängige Test-Automatisierung. Hier erfahren wir am eigenen Leib was es bedeutet, Tests nicht zu automatisieren. Vor allem weil wir das (Fern-)Ziel eines Continuous-Delivery verfolgen ist es für uns unabdingbar, das Thema weiter voranzutreiben und so viele Tests wie möglich zu automatisieren.
Habt ihr nach dem Lesen des Artikels noch Fragen? Seid ihr mit einem Aspekt nicht einverstanden oder seht ihr weitere Vorteile / Nachteile bei der Testautomatisierung? Wir freuen uns über euer Feedback in den Kommentaren und wünschen euch viel Spaß beim Ausprobieren.
Eure Spaß-Coder
Dieser Artikel basiert neben unseren Erfahrungen auf folgenden Quellen:
- http://de.wikipedia.org/wiki/Modultest
- http://de.wikipedia.org/wiki/Integrationstest
- http://de.wikipedia.org/wiki/Regressionstest
Verwendete Bilder:
Mischpult: https://www.flickr.com/photos/95213174@N08/13296791174/
Achterbahn: https://www.flickr.com/photos/buschap/3960386389
Traffic Light Tree in the Docklands: https://www.flickr.com/photos/46239552@N00/4852958993
Traffic Light Tree in the Docklands nachts: https://www.flickr.com/photos/wwarby/2460655511/