Zehn Verfahren zum effektiven Testen von Benutzeroberflächen
Benutzeroberflächen frühzeitig ausgiebig zu testen zahlt sich im weiteren Verlauf von Projekten aus. Neben Kosteneinsparungen bei der Wartung tragen solche Tests zu einer benutzerfreundlichen Anwendung bei, die effektiv ist und deren Verwendung keine unliebsamen Überraschungen bereithält.
- Phil Quitslund
Benutzeroberflächen frühzeitig ausgiebig zu testen zahlt sich im weiteren Verlauf von Projekten aus. Neben Kosteneinsparungen bei der Wartung tragen solche Tests zu einer benutzerfreundlichen Anwendung bei, die effektiv ist und deren Verwendung keine unliebsamen Überraschungen bereithält.
Die Benutzeroberfläche (User Interface, UI) einer Softwareanwendung ist die direkte Schnittstelle zwischen System und Anwender. Sie muss ansprechend gestaltet sein und gleich von Anfang an eine effektive Arbeit ermöglichen. Tut sie das nicht, wirkt sich das unmittelbar auf das Ansehen eines Unternehmens aus. Das Ziel beim Erstellen von UI-Tests ist die umfassende Prüfung der gesamten Benutzeroberfläche einer Anwendung unter Berücksichtigung der Frage, ob sie wie geplant funktioniert. Am Ende des Test- und Prüfprozesses sollte eine benutzerfreundliche Anwendung stehen, die zuverlässig arbeitet und keine unliebsamen Überraschungen bereithält. Effektives Testen sollte außerdem zu einer Reduzierung der Wartungskosten beitragen. Vor diesem Hintergrund sei jedoch betont, dass es bei UI-Tests große Unterschiede gibt.
Im Folgenden werden zehn geeignete Verfahren zur Entwicklung effektiver und einheitlicher UI-Tests vorgestellt.
1. Frühzeitig und häufig testen
Je früher man im Entwicklungsprozess einen Test durchführt, desto geringer sind die Gesamtkosten zur Behebung von Fehlern. Die Kosten für das Beseitigen eines Fehlers in einer beim Kunden bereitgestellten Anwendung ist 15-mal höher, als wenn das Beheben während der Entwicklung des Softwarecodes vorgenommen wird [1]. Nach einem Bericht von Capers Jones [2] verursachen Arbeiten im Zusammenhang mit falschen Anforderungen und Entwürfen sowie Codefehlern in der Regel mindestens 40 bis 50 Prozent der Gesamtkosten von Softwareprojekten. Damit sind sie der größte einzelne Kostentreiber. Frühe Tests sind also definitiv die richtige Lösung.
2. Kerndomäne und Plattformdetails voneinander isolieren
Die Tests der Programmlogik sind möglichst separat von den Darstellungsdetails der UI testen. Das ist zwar nicht einfach, aber es lohnt sich. Es lassen sich beispielsweise mit Einzeltests Interaktionen so gering wie möglich halten, und es sorgt dafür, dass der Anwendungskontext weitgehend auf die einzelnen Tests beschränkt bleibt. Die Entkopplung von Modell und Ansicht erleichtert die Durchführung und die Entwicklung verlässlicher und nachvollziehbarer UI-Tests. Darüber hinaus lassen sich auf die Weise Testkonfigurationen mehrmals nutzen. Des Weiteren führt die Isolierung zu einem ausgereifteren und "sauberen" Softwarecode für das Kernmodell.
Ein Beispiel sei anhand von Eclipse gebracht: Bei der IDE lässt sich ein Test als eigenständiger JUnit- oder als PDE-Test (Plug-in Development Environment) – das heißt innerhalb der Eclipse-Umgebung – durchführen. Wenn man die Kerndomäne von den Plattformdetails isoliert und die Anwendung so weit wie möglich außerhalb des PDE-Kontexts testet, ist kein Plattform-Bootstrapping erforderlich. Tests außerhalb der PDE gehen deswegen schneller vonstatten, und es besteht eine größere Wahrscheinlichkeit, dass die Entwickler sie kontinuierlich ausführen können.
Zentraler Code, der sich außerhalb der PDE testen lässt, enthält in der Regel auch weniger Verweise auf Frameworks. Dadurch wird das Kernmodell zu einem stärker in sich geschlossenen Produkt, das flexibler ist und sich besser in anderen Kontexten einsetzen lässt.
3. Interaktion von Modell und Framework testen
Indem man insbesondere bei Eclipse-Anwendungen dafür sorgt, dass das Modell korrekt mit dem Framework interagiert, lässt sich sicherstellen, dass das System als Ganzes das erwartete Verhalten zeigt. Hierfür sind eine Reihe von Integrationstests notwendig, die den Modellcode möglichst intensiv testen. Bei Eclipse interagieren diese Tests mit Plattformservices und sie sind im Kontext der PDE durchzuführen. In der Praxis lassen sich die Tests weniger regelmäßig auf Entwicklerrechnern (beispielsweise vor der Übertragung von neuem Code in das Quell-Repository) und "remote" auf einem Testrechner im Rahmen eines kontinuierlichen Erstellungsprozess durchführen.
4. Härtetests planen
Automatisierte Test-Frameworks nehmen dem Entwickler zahlreiche, immer wiederkehrende Aufgaben beim Testverfahren ab. Sobald er die Frameworks eingerichtet hat, sollte er sie einem Härtetest unterziehen. Dieser kann zum Beispiel darin bestehen, alle Prozessbeteiligten (Entwickler, Designer, Tester und Manager) an einem Ort zu versammeln und das Produkt einem echten Härtefall zu unterziehen. Die Vorgehensweise, die auch als "Bug Bash" bezeichnet wird, ist beliebt und effektiv. Diese Tests fördern häufig Probleme zutage, die die Teams bei formalen Testplänen und Brauchbarkeitsprüfungen gar nicht berücksichtigt hatten.
5. Tests robust gestalten
Tests, die heute funktionieren, sollten morgen ebenfalls keine Defekte aufweisen. Hierzu gibt es nicht viel zu sagen, von einigen grundlegenden Empfehlungen abgesehen:
- Es empfiehlt sich, mit Bedingungen zu arbeiten: Pausen mit festgelegter Dauer sind in der Regel problematisch. Zur Ermittlung von Fakten über die getestete Anwendung sowie als Methode zur Durchsetzung unveränderlicher Aspekte sollten Entwicklungsteams Bedingungen einsetzen. Wenn der Zeitfaktor die große Unbekannte ist, beispielsweise in einer Multi-Threading-Anwendung, lässt sich mit einer Bedingung das Eintreten eines bestimmten Ereignisses oder Status anstelle einer festen Wartedauer festlegen (siehe Abbildung 1).
- Weiterhin sollte man Handler verwenden: Bisweilen kommt es in Anwendungen zu nicht vorhersehbaren interaktiven Ereignissen – beispielsweise wenn eine Warnmeldung angezeigt wird, die zu bestätigen ist, bevor der Test fortgesetzt werden kann. Auf diese bekannten, aber dennoch unvorhersehbaren Situationen lässt sich mit einer Kombination aus Bedingung und Handler (Behandlungsroutine) eingehen. Dadurch sinkt die Gefahr, dass während des Tests etwas schief läuft.
- Schließlich ist es anzuraten, im Testmodus beziehungsweise mit einer Bedingungsüberwachung zu arbeiten: In einigen Situationen ist es sinnvoll, die Möglichkeit zum Umgang mit unerwarteten Situationen zu integrieren. Hierfür muss in der Anwendung ein Testmodus eingerichtet werden, bei dem das Test-Framework Informationen dazu enthält, welche Verhaltensweisen die Anwendung ignorieren soll und wann der normale Betrieb fortgesetzt wird. Auf die Weise erleichtert beispielsweise das Informationsdialog-Framework Eclipse JFace die Testverfahren. Sollte man sich den Luxus eines Testmodus nicht leisten können, kommt eventuell der Einsatz einer Bedingungsüberwachung in Frage. Damit behält man sämtliche Bedingungen im Blick – und im Griff. Die Implementierung eines Systems zur Bedingungsüberwachung zeigt die Abbildung 2.