Automatisierung des Tests von Java-Swing-GUIs
Transcription
Automatisierung des Tests von Java-Swing-GUIs
Automatisierung des Tests von Java-Swing-GUIs Ausarbeitung Aktuelle Themen der Informatik Prof. Dr. Friedbert Kaspar HFU - Hochschule Furtwangen University Robert-Gerwig-Platz 1 78120 Furtwangen Dominik Jall Fakultät Computer Networking (CN 7) Matrikel Nr. 216385 E-Mail: [email protected] Pflichtveranstaltung CN 8 Sommersemester 2006 1 Inhaltsverzeichnis Vorwort..........................................................................................................................3 Einleitung.......................................................................................................................4 Warum GUIs automatisiert testen?................................................................................5 Werkzeuge und Methoden.............................................................................................7 QftestJUI........................................................................................................................9 Andere Ansätze............................................................................................................11 Fazit.............................................................................................................................13 Quellen.........................................................................................................................14 2 Vorwort „Ein weitverbreiteter Fehler, den Menschen begehen, wenn sie etwas vollkommen Narrensicheres entwickeln, ist den Einfallsreichtum vollkommener Narren zu unterschätzen.“ Douglas Adams 3 Einleitung „Softwaresysteme werden durch den Anwender heute meist über grafische Benutzerschnittstellen (GUI, Graphical User Interface) gesteuert. Aufgrund der vielfältigen Anwenderinteraktionen und der grafischen Kontrollelemente in der GUI sind wohldefinierte Testszenarien komplex und daher schwer umzusetzen. Solche Tests sind zeitraubend und kostenaufwändig. Kein Entwickler ist zudem erfreut, wenn er alle Interaktionen manuell austesten und dokumentieren muss, da solche Tests nicht nur monoton, sondern auch entsprechend arbeitsintensiv sind. Abhilfe schaffen hier Werkzeuge, die solche Szenarien automatisieren, so genannte GUI Capture & Replay-Werkzeuge.“ [1] Mittlerweile hat sich durch die zunehmende Anwendung von Methoden aus den Ingenieurwissenschaften das ständige Testen von Software auch bereits während des Entwicklungsprozesses verbreitet. Nicht zuletzt durch moderne Ansätze wie „Extreme Programming“ [2] oder „Testgetriebene Programmierung“ [3] und den andererseits ständig an Komplexität zunehmenden Softwareprojekten spielt das Testen von Software heutzutage eine große Rolle im Entwicklungsprozess. Dennoch spielt derzeit das intensive Testen von GUIs, also den grafischen Benutzeroberflächen eine eher untergeordnete Rolle, vielmehr konzentrieren sich die Testszenarien eher auf Programmlogik, Datenintegrität und Threadsicherheit. Das liegt zum einen daran, dass GUIs in Projektgruppen oft eher als weniger wichtig angesehen werden, schließlich werden sie nicht zur Abhandlung der Algorithmen und Kernprozesse eines Programms benötigt, sie könnten genauso gut durch einfache Funktionsaufrufe mit entsprechenden Parametern ersetzt werden, den nichts anderes vollführen sie „unter der Haube“: Der Benuter klickt auf einen Knopf, der Klick löst den Aufruf einer bestimmten Methode auf, die die Geschäftslogik dahinter implementiert. Da GUIs oft icht von den Entwicklern der Logik sondern von Designern erstellt werden herrscht hier naturgemäß ein Kommunikationsproblem vor, man ist sich „Art-fremd“. Auf der anderen Seite bestehen neben diesen, eher psychologischen, Problemen handfeste Probleme bei der Implementierung von GUITests. Da eine GUI ein interaktives Medium ist, dass Eingaben eines Benutzers benötigt, um seinen Sinn und seine Aufgabe zu erfüllen, andererseits aber kein fest vorgegebener Ablauf in der Bedienung vorgegeben sein muss, steht der Entwickler von Testfällen hier vor einer komplexen Aufgabe, die viel Wissen, sowohl um Programmierung als auch um „den Benutzer“ erfordert. 4 Warum GUIs automatisiert testen? Nach den oben erwähnten Problemen bei der Ausweitung von Tests auch auf grafische Benutzeroberflächen, bei gleichzeitig scheinbar geringem Nutzen für die Software, warum sollten Firmen dennoch das GUI-Testing, insbesondere die Automatisierung des Testings in Betracht ziehen? Zum einen wird durch GUI-Testing die Testabdeckung des Softwaresystems erhöht. Es kann danach nicht nur von getesteter Logik, Datenbankzugriffen und Integrität ausgegangen werden, sondern auch von einer stabilen GUI, die garantiert das tut was sie soll. Andererseits kann die Sicherheit des gesamten Programms erhöht werden, indem „Schlupflöcher“ (z.B: in Anmeldedialogen) verhindert werden. Zu guter Letzt, ein nicht unerheblicher Faktor, kann die GUI bereits „vorgetestet“ werden, bevor der erste menschliche Tester sie zu Gesicht bekommt. So können die gröbsten Design oder Implementierungsprobleme im Vorfeld zeit- und kostensparend ausgemerzt werden. Dennoch: Dies alles könnte auch intern durch menschliche „Vortester“ bewerkstelligt werden – warum also automatisiert testen? Ich schreibe diese Ausarbeitung aus der Sicht der Anwendungsentwickler. Ich habe bereits einige kleinere und größere GUIs für diverse Projekte entworfen und getestet und ich denke ich spreche für einen Großteil der Entwicklergemeinde, wenn ich behaupte, dass dies kein besonders kreativer oder motivierender Teil der Arbeit ist. GUIs zu testen kostet Zeit, Nerven und erzeugt ausserdem eine Menge schlecht zu lesenden Code (insbesondere bei der Verwendung sog. „GUI-Editoren“, wie etwa [4] oder [5]). Andererseits kann wohl kein Mensch alle Schwachstellen und „Bedienungs(un)arten“ einer GUI testen, geschweige denn fielen sie ihm alle ein (siehe Vorwort). Das Entwerfen von Testfällen für GUIs ist also nicht nur zeitaufwändig und erfordert viel „negativer Kreativität“ („was kann ich alles falsch machen?“), viel schlimmer noch: Am Ende dieses aufreibenden Vorgangs kann sich der Entwickler nicht mal sicher sein, dass seine GUI jetzt hundertprozentig getestet ist. Letztlich muss beim Testen der GUI, wie bei jedem anderen Test auch immer nur ein kleiner Teil des Systems verändert werden, beispielsweise ein Textfeld enthält einen anderen Wert oder eine Checkbox wird aktiviert. Nach jeder Veränderung muss erneut getestetet werden, um festzustellen, wo genau ein Fehler liegt, ähnlich wie bei einem wissenschaftlichen Experiment. Beim Testen von Code kann hier der Monotonie durch geschickt programmierte Schleifen oder rekursive Aufrufe abgeholfen werden, die Datenstrukturen mit immer anderen Werten füllen. Beim GUI-Test aber müsste stetig ein Knopf gedrückt oder ein Regler verschoben, dann das Programm neu geladen und wieder etwas verändert werden. Dass hierbei keine Freude aufkommt muss wohl niemanden wundern. 5 All diese Nachteile manueller Tests machen in professionellen Umgebungen, die oft sehr GUIintensive Software entwickeln die Automatisierung von GUI-Tests zu einem Muss. Weitere Gründe sind: • Reduktion des manuellen Aufwands • Reduktion der Testkosten • Reproduzierbarkeit • Qualitätsverbesserung [1] 6 Werkzeuge und Methoden: Capture & Replay Welche Möglichkeiten bietet der Markt zum automatisierten Testen von Benutzeroberflächen? In dieser Ausarbeitung möchte ich näher auf die sog. „Capture & Replay“ Tools eingehen. Dabei handelt es sich, vereinfacht gesagt, um Softwarewerkzeuge, die dynamisch GUIs laden können und (je nach Ausprägung) einige bis sämtliche Interkaktionen, die der Nutzer mit der GUI machen kann aufzeichnen und zu einem späteren Zeitpunkt wieder „abspielen“ können. Dabei können an definierten Punkten sog. „Checks“ eingebaut werden, die zu diesem Zeitpunkt bestimmte Zustände der GUI überprüfen und folgende Zustände einnehmen können: • Check OK – Der Zustand ist wie erwartet. • Check Exception – Der Zustand liefert einen erwarteten Fehler, es ist also der Check fehlgeschlagen, weil die GUI nicht den gewünschten Wert liefert. • Check Error – Der Zustand ist unerwartet fehlerhaft. Nicht der „gewünschte Fehler“ trat ein, sondern ein anderer, nicht geplanter Zustand trat ein. Die „Replay“ Funktion der Tools agiert dabei wie ein „echter“ Benutzer, sie simuliert also Mausklicks oder Tastatureingaben ganz so, als würde ein Mensch vor dem Programm sitzen, nur eben viel schneller und präziser. In meinem Fall, also dem Testen von Swing-GUIs bietet Java von Haus aus eine Schnittstelle, mit der bequem Eingaben des Benutzers simuliert werden können, nämlich die Klasse java.awt.robot. [6] Um diese Klasse, sowie um das Junit-Framework [12] sind bisher eine ganze Reihe brauchbarer Werkzeuge entstanden, von denen ich hier besonders auf das QftestJUI der Firma QualityFirst [7] eingehen möchte, da hier die Bedienung besonders intuitiv und anschaulich ist. Aber auch die anderen (meist Opensource-) Werkzeuge sollen im Abschnitt „Andere Ansätze“ Erwähnung finden. Die weiteren grundlegenden Anforderungen an C&RWerkzeuge sind: • Capture Mode • Programming Mode • Checkpoints und • Replay Mode Neben den bereits erläuterten Modi existiert noch der „Programming Mode“, mit dem es möglich sein soll, auch komplexe Testszenarien zu implementieren, als nur das simple „Abspielen“ von Tests. 7 Folgende Eigenschaften zeichnen das Tool von QFS aus: • GUI-basiert, daher intuitiv zu bedienen • Kommerziell • Kann Reports in HTML generieren, was eine weitere Verarbeitung der Reports vereinfacht • Registriert sämtliche Reaktionen der Anwendung auf die simulierten Aktionen (Exceptions etc.) • Kostenlose Evaluierungsversion, was insbesondere den Entscheidungsträgern in einem Softwareprojekt hilft, die Nutzen mit den eventuellen Kosten des Tests abzuwägen. Da es sich um kommerzielle Software handelt sollten vor der Einführung des Werkzeugs unbedingt noch offene Fragen geklärt werden, damit hinterher nicht die Kosten den Nutzen überwiegen: • Verursacht die Automatisierung höhere Kosten als der manuelle Test? Wie viel mehr? • Automatisierte Tests haben eine begrenzte Lebensdauer. Wie lange wird das Testszenario gültig sein? • Während der Gültigkeit des Testszenarios können weitere Fehler entdeckt werden, die in vorangegangenen Durchläufen nicht auftauchten. Wie groß ist dieser Nutzen gegenüber den Mehrkosten der Automatisierung? [1] Können diese Fragen zugunsten einer Automatisierung des Testprozesses beantwortet werden, steht einer breiteren Einführung des Werkzeugs mit den damit verbundenen Änderungen im Entwicklungsprozess nichts mehr im Wege. Es sei jedoch gesagt, dass sich die automatisierte Herangehensweise nicht immer lohnt. Dazu sollte die GUI der Software bereits einigen Umfang sowie eine höhere Komplexität haben. Ein Anmeldedialog oder ein einfaches Fenster ohne weitere zusätzliche Interaktionsmöglichkeiten kann als zu gering erachtet werden, als dass sich der Aufwand der Automatisierung lohnen würde. In einem solchen Fall würde ich eher den Einsatz einer kostenlosen OpenSource-Alternative empfehlen wie z.B. jfcUnit [8] oder Marathon [9] 8 QFtestJUI Abbildung 1 zeigt einen Screenshot des Hauptfensters des Programms. Abbildung 1: qftestJUI Zur Erläuterung: In der Mitte des Fensters auf der linken Seite ist eine Baumstruktur der gesamten Testsuite zu sehen. Dabei werden sowohl die eigentlichen Tests, wie auch die abzuspielenden Sequenzen (Test) oder zusätzliche Konfigurationseinstellungen, die nicht direkt etwas mit dem eigentlichen Testen zu tun haben dargestellt. Dazu gehören etwa Einstellungen zur JVM, die benötigt werden, um die zu testenden GUI-Klassen erst zu laden. (Extrasequenzen). Auf der rechten Seite wird der Inhalt der linken Seite zur Bearbeitung dargestellt. Im Bild kann man sehen, dass hier benötigte Dateien für die Testsuite, also Includefiles, andere Abhängigkeiten, Variablen wie z.B. Classpath etc. gesetzt werden können. Ist die GUI einmal geladen, kann im Abschnitt „Fenster und Komponenten“ eine hierarchische Baumdarstellung der Oberfläche gefunden werden. Sie dient mehr der Übersicht über komplexere GUIs. Der grüne „Play“-Knopf startet die GUI, bzw. das Abspielen von 9 aufgezeichneten Sequenzen oder Tests. Der grüne Haken wird benutzt, um in den „Check-Modus“ zu schalten. Es können dann bei laufender GUI einzelne Checks für Komponenten festgelegt werden. Der rote „Recording“-Knopf wird benutzt, um Sequenzen des virtuellen Benutzers aufzuzeichnen, der später anstelle eines echten Testers die Knöpfe und Schalter des Programms betätigt. Zusammen mit den Checks läuft somit eine komplett automatische Testreihe der GUI ab, Die am Ende im Menü „Wiedergabe“->“Protokoll“ nachverfolgt werden kann. Dort finden sich u.a. ein Report über alle Warnungen und Fehler, die während des Tests auftraten, zusammen mit einem Zeitstempel und einem Screenshot der GUI zum Zeitpunkt des Fehlers. Die Knöpfe auf der rechten oberen Seite haben die übliche Bedeutung beim Debugging: Step into, Step over, Step out, etc. nur eben in diesem Fall nicht für einzelne Codezeilen, sondern für Testabschnitte, bzw. aufgezeichnete Sequenzen. So muss z.B. nicht jedes Mal der gesamte Test durchlaufen werden, wenn nur in einem bestimmten Bereich etwas nicht erwartungsgemäß abläuft. Dies ist sehr hilfreich, da GUI-Tests, wie Softwaretests allgemein, teilweise sehr umfangreich und langwierig sein können und bis zu mehreren Stunden Zeit benötigen. Jede einzelne Sequenz kann hierbei in einem Eigenschaftsfeld modifiziert werden. Testsuites und Protokolle werden als XML-Dateien gespeichert, d. h. als normaler Text in wohldefinierter Syntax. Zum Suchen und Ersetzen und bei der Überprüfung von Daten, die an der Oberfläche angezeigt werden, können reguläre Ausdrücke verwendet werden. Anstelle der fest verdrahteten Texteingaben für Eigenschaftswerte können auch variable Werte verwendet und die aufgenommene Sequenz in eine Prozedur umgewandelt werden. Auf diesem Weg lassen sich schnell datengetriebene Tests erstellen, die immer wieder dieselbe Sequenz durchlaufen, aber jedes mal mit anderen Daten. Diese können z. B. aus einer Datei oder einer Datenbank gelesen werden. Aktionen, die der Anwender ausführt, werden von der Java VM in Events umgewandelt. Jeder Event hat eine Zielkomponente. Für einen Mausklick ist das die Komponente unter dem Mauszeiger, für einen Tastendruck die Komponente, die den Tastaturfokus (keyboard focus) besitzt. Wenn qftestJUI einen Event aufzeichnet, nimmt es zusätzlich Informationen über die Zielkomponente mit auf, sodass die Komponente später beim Abspielen des Events wieder lokalisiert werden kann, selbst wenn sich einige Parameter wie Größe oder Lokation geändert haben. Dies ist insbesondere dann Hilfreich, wenn Regressionstests mit komplexen Anwendungen durchlaufen werdens sollen, deren Testfälle ständig auch bei veränderten GUIs durchlaufen werden müssen, ohne dass das Testprogramm aus dem Tritt kommt. 10 Andere Ansätze Neben qftestJUI finden sich derzeit noch einige Alternativen, die aber allesamt den Nachteil einer schlechteren Bedienbarkeit mangels GUI haben. Dennoch stehen die meisten dem kommerziellen Tool in nichts nach und professionelle Programmierer, die bereits Erfahrungen mit Junit gesammelt haben dürften mit der Integration in das eigene Projekt keine Schwierigkeiten haben. Marathon [9] Marathon erfasst semantische Aktionen, die auf Komponenten ausgeführt werden, anstatt sich auf Tastatur und Mausevents zu konzentrieren. Marathon besteht aus einem Recorder, einer Ablauflogik und einem Editor. Die Testskripts sind in Python aufgebaut. [1] Der Editor von Marathon bietet eine rudimentäre GUI, mit der die wichtigsten Einstellungen gemacht werden können, ist jedoch keinesfalls als ähnlich ausgereift wie der von qftestJUI zu bewerten. Der Vorteil liegt in der semantischen, also sinnhaften Erfassung der Aktionen. Dadurch bietet Marathon eine größere Flexibilität als reine Keyboard- oder Mauslogger. Pounder [10] Pounder ermöglicht dynamisches Laden von GUIs, die Aufzeichnung von Skripten und deren Wiederverwendung in Testframeworks wie JUnit. Pounder unterliegt der GNU Library General Public License (LGPL) [11] und ist somit frei verfügbar. [1] Pounder verfügt ebenso wie Marathon über eine rudimentäre GUI, welche Swing-basiert ist und kann Testfälle und -suites für Junit erzeugen. Mittlerweile wird das Projekt jedoch nicht mehr aktiv weiterentwickelt, die Homepage verweist auf andere Tools, unter anderem auf Marathon und jfcUnit. JcfUnit [8] jfcUnit ist eine Erweiterung des JUnit Frameworks, die es ermöglicht Unit-Tests mit SwingKomponenten zu verbinden. jfcUnit verwendet XML zur Aufzeichnung seiner Tests. [1] Dem Entwickler, der ständig schon durch den herkömmlichen Testprozess seiner Software mit Junit zu tun hat wird die Integration von jfcUnit leicht fallen, da es sich dabei schlicht um eine um SwingKomponenten erweiterte Junit-Version handelt. JfcUnit hilft dabei den Entwicklern, Testfälle für Swing-basierte Applikationen zu schreiben und unterstützt: • Das Mitschneiden von Fensterhandles und Ids von Komponenten, die durch den Javacode des Projekts erzeugt wurden. • Das Auffinden von Komponenten innerhalb einer Objekthierarchie der darüber liegenden Container. 11 • Eventraising auf den gefundenen Komponenten, also Aktionen wie Klick auf Knöpfe, Texteingaben etc. • Thread-sicheres Handlich von Tests (Checks) auf Komponenten. Neben den erwähnten findet sich noch eine Vielzahl kleinerer Projekte im Netz, es handelt sich bei den vorgestellten Tools lediglich um eine kleine Auswahl. Dennoch bleibt zu sagen, dass die meisten kleineren, und meist quelloffenen Tools sich nur zum Test kleinerer Softwareprojekte eignen und für größere und komplexere Anwendungen die Wahl eines teureren, proprietären Werkzeugs mit Support vom Hersteller auf jeden Fall bedacht werden sollte. 12 Fazit In dieser Ausarbeitung habe ich anhand eines professionellen Werkzeugs und kleinerer, freier Tools das Thema „Automatisiertes Testen von Swing-GUIs“ erläutert. Es sei gesagt, dass sich das Thema „Testing“ immer mehr in den Vordergrund aktueller Softwareprojekte schiebt und sich so zu einem zentralen Punkt des Softwareengineering entwickeln wird. Nur durch ständiges Absichern und Testen kann bei der Komplexität heutiger Großprojekte noch die Sicherheit und Qualität gewährleistet werden. Menschen machen natürlich Fehler und die werden sie wohl immer machen, aber durch die Unterstützung einer Software kann bereits heute ein Großteil der gröbsten Fehler im Design und in der Implementierung von Komponenten verhindert werden. Nicht zuletzt durch den ständig ansteigenden Anteil an zugekauften Features, die nicht im eigenen Haus entwickelt wurden („Make or Buy“) muss sich das obligatorische Testen von GUIs im gesamten Bereich der Komponentenentwicklung durchsetzen, da sonst auf lange Sicht die Qualität der Software insgesamt leidet. Für das Testen in komplexen Applikationsentwicklungen ist es unabdingbar, die grafischen Nutzerschnittstellen zu erproben. Dies sollte sowohl in einem Akzeptanztest der zukünftigen Anwender als auch in einem funktionalen Test innerhalb der Systemlogik geschehen. Für diesen Zweck werden diverse CR-Werkzeuge zur Verfügung gestellt, und im Hinblick auf Kostenreduktion durch Testautomatisierung sind diese Toolinvestitionen durchaus gerechtfertigt. Nichts desto trotz steht die Software, die diese Prozesse unterstützt noch relativ am Anfang und es muss sich erst noch zeigen, was die „best practises“ der softwaregestützten Automatisierung von GUIs in modernen Anwendungen sind. 13 Quellen [1] Javaspektrum 6 / 2004, Titelthema [2] „Extreme Programming“ - http://de.wikipedia.org/wiki/Extreme_Programming [3] „Testdriven Development“ - http://de.wikipedia.org/wiki/Testgetriebene_Entwicklung [4] VisualEditor - http://www.eclipse.org/vep/WebContent/main.php [5] NetBeans - http://www.netbeans.org/ [6] java.awt.robot - http://java.sun.com/j2se/1.5.0/docs/api/java/awt/Robot.html [7] Quality First Software - http://www.qfs.de/ [8] jfcUnit http://jfcunit.sourceforge.net/ [9] Marathon - http://marathonman.sourceforge.net/ [10] Pounder - http://pounder.sourceforge.net [11] GPL, LGPL - http://www.gnu.org/licenses/licenses.html [12] Junit - http://www.junit.org/index.htm 14