Mit der zunehmenden Agilität in der Softwareentwicklung und somit immer kürzeren Entwicklungszyklen sind manuell durchgeführte Oberflächentests oft nicht mehr umfassend möglich oder wirtschaftlich angemessen. Die automatisierte Ausführung dieser Tests nimmt deshalb in Unternehmen eine zunehmend wichtige Stellung ein.
Automatisierte Oberflächentests bringen dort den größten Nutzen, wo früher manuelle Tester mühselig nach einem vorgegebenen Testplan die Software (teilweise mehrfach auf unterschiedlichen Umgebungen) abgeklickt und geprüft haben. Sie eignen sich jedoch nicht unbedingt dazu, die subjektiven Eigenschaften einer Software zu testen, sprich den menschlichen Umgang damit (Usability / User Experience).
Die Vorteile von Testautomatisierung
Die Umstellung von manuellen auf automatisierte Oberflächentests kann und sollte nicht beiläufig passieren, da sie einen großen Initial- und laufenden Pflegeaufwand benötigt. Dieser Aufwand zahlt sich jedoch langfristig nicht nur monetär, sondern auch qualitativ aus und legt die Basis für eine gute und beständige Softwarequalität.
Die Testautomatisierung hilft nämlich nicht nur dabei, die Oberflächentests ressourcenschonend und beliebig oft wiederkehrend ausführbar zu machen, sie hilft auch dabei, menschliche Fehler, die beim manuellen Testen entstehen können, zu reduzieren und je weniger Fehler die Software hat, desto glücklicher sind die Kunden.
Außerdem sind die Fachexperten, die vorher manuelle Tests durchführten, es nicht mehr leid, in einer hoch monotonen Folge Testpläne abzuarbeiten. Sie haben nun mehr die Möglichkeit, neu hinzugekommene Funktionen ausgiebig zu testen oder tiefer gehende User Experience-Analysen durchzuführen, um die Erwartungshaltung der Kunden an die Software zu erfüllen oder sie möglicherweise sogar darüberhinaus zu begeistern.
Auch erfahren die Softwareentwickler eine wunderbare Unterstützung bei ihrer Entwicklungsarbeit: Durch die Einbindung der Testautomatisierung in ihre Continuous Integration bzw. Delivery Pipeline erhalten sie ständiges Feedback über den Zustand der entwickelten Software und ihrer Codeänderungen, und somit mögliche Anknüpfungspunkte für die Fehlersuche und die anschließende Fehlerbehebung.
Spezielle Test-Frameworks unterstützen die Realisierung automatisierter Oberflächentests sehr gut. Bis auf einige Ausnahmen sind die meisten dieser Frameworks jedoch kostenpflichtig und teilweise auch komplex in der Handhabung bzw. Integration in die eigene IT-Landschaft.
Selenium: Einfach handhabbar und kostenfrei
In diesem Artikel stelle ich euch deshalb das einfach handhabbare und kostenfrei unter der Apache-2.0-Lizenz veröffentlichte Framework Selenium vor, das sich insbesonders für die Automatisierung browserbasierter Oberflächentests eignet. Weitere OpenSource-Projekte wie Appium oder Protractor bauen ebenso auf Selenium auf und ermöglichen die Testautomatisierung von nativen und hybriden mobilen Apps. Auf diese Erweiterungen wird hier nicht weiter eingegangen.
Ich persönlich habe Selenium mittlerweile in drei Softwareprojekten erfolgreich eingeführt, eingesetzt bzw. erweitert und bin von seinem funktionellen Umfang und der einfachen Bedienbarkeit begeistert. Auch höre ich immer wieder im Austausch mit Kollegen, dass sich Erfolgserlebnisse sehr schnell einsetzen und es auch ihnen auf Dauer richtig Spaß macht, mit Selenium eigene Oberflächentests zu entwickeln. Letztere Punkte sind eigentlich schon Gründe genug, sich dieses Framework näher anzuschauen, da die Akzeptanz bei denen, die sich täglich damit beschäftigen müssen, für den Erfolg einer Automatisierungsstrategie entscheidend ist.
Eine kleine Randnotiz:
Die nachfolgenden Quellcode-Beispiele basieren auf Java und die weiteren Beschreibungen sowie die Namensgebung beziehen sich auf den Versionsstand 3.x von Selenium. Diese Information ist wichtig, da Selenium 1 mit dem mittlerweile „deprecated“-Modul „Selenium RC“ architektonisch anders und im Vergleich weniger performant und unflexibler aufgesetzt war.
Die Architektur bietet eine hohe Flexibilität
Die große Akzeptanz und der Erfolg von Selenium liegt neben der OpenSource-Veröffentlichung sicher auch darin begründet, weil damit auf den gängigsten Betriebssystemen (Windows, Linux und OS X) sowie den am meist verbreitetsten Browsern (Mozilla Firefox, Internet Explorer, Google Chrome, Opera, Safari, etc.) Oberflächentests durchgeführt werden können.
Darüberhinaus bietet es die Flexibilität, die Testskripts in beliebigen und unterschiedlichen Programmiersprachen (auch innerhalb desselben Projekts) zu erstellen und diese durch den Selenium WebDriver in ausführbare Tests übersetzen zu lassen.
Seit der Version 2 wurde mit Selenium Grid außerdem die Möglichkeit der parallelen und verteilten Ausführung der Testskripts geschaffen. Dieser neue Ansatz ermöglicht neben hoher Testdurchsätze auch die Sicherstellung einer hohen Verfügbarkeit der Testsysteme.
Selenium im praktischen Einsatz
Die Einbindung von Selenium, bspw. in ein Java-Projekt erfolgt ganz einfach über Maven. Jedes Testvorhaben startet dann mit der Erstellung eines Testskripts. Ein Testskript kann u.a. mit dem Testframework JUnit erstellt werden und enthält neben den Testbefehlen, auch die anschließende Evaluierung der Ergebnisse. Die Testbefehle beschreiben die gewünschten Nutzeraktionen, die Selenium später auf der Anwendung, dem Testobjekt, simulieren soll.
Die für das Testskript verfügbaren Testbefehle werden dabei vom entsprechenden Client API gezogen, das für die gängigsten Programmiersprachen bereitgestellt wird. Gängige Praxis ist aber auch, dass das Testskript mit einem PageObject interagiert, das eine bestimmte Seite der Anwendung repräsentiert und die für diese Seite notwendigen WebDriver-Funktionalitäten in sich kapselt (weiterführende Infos zum PageObject-Pattern).
Selenium IDE
An dieser Stelle wollen wir es nicht unerwähnt lassen: Für die Erstellung der Testbefehlsketten gibt es nämlich auch ein semi-hilfreiches Tool namens Selenium IDE, welches eigentlich ein Add-On für die Browser Firefox und Chrome ist. Dieses Add-On kann die auf der zu testenden Anwendung ausgeführten Aktionen aufzeichnen, wieder abspielen und als generisches Testskript bereitstellen. Es ist somit eine Art Makro-Editor für browserbasierte Anwendungen und stellt kein Tool dar, das die Testautomatisierung steuert und verwaltet (wie der Name vielleicht vermuten ließe).
Im Alltag wird der ein oder andere Entwickler deshalb möglicherweise schnell merken, dass er mit dem Tool auf seine Grenzen stößt. Es hilft einem jedoch dabei, einen ersten Wurf eines Testskripts zu erstellen, anschließend in eine der unterstützen Programmiersprachen zu exportieren und im eigenen IDE weiter zu verfeinern.
Selenium WebDriver
Bei der Ausführung eines Testskripts werden die einzelnen Befehle, die normalerweise ein manueller Tester ausführen würde, vom Selenium WebDriver peu Ü peu interpretiert und über den Browser in die entsprechenden Aktionen in der Anwendung umgesetzt.
Die einzelnen WebElemente in der Anwendung werden dabei zuerst über unterschiedliche Wege lokalisiert (FindBy-Methoden, u.a.). Auf diesen Elementen können dann abhängig vom Elementtypen unterschiedliche Aktionen ausgeführt werden.
Beispiel: Die zu testenden Elemente werden in der Anwendung lokalisiert [1,4] und anschließend werden darauf Aktionen ausgeführt [2,3,5].
[1] WebElement element = driver.findElement(By.name("elementID")); [2] element.click(); [3] element.sendKeys("MyUsername"); [4] WebElement submitElement = driver.findElement(By.id("submit")); [5] submitElement.click();
Die obigen Zeilen in Worten ausgedrückt: „Lokalisiere das Element mit dem Attributsnamen ‚elementID‚, klicke in das Element und gebe darin den Text ‚MyUsername‘ ein. Lokalisiere danach das Element mit der ID ’submit‘ und klicke darauf.“. Um dem Test noch einen Sinn zu verleihen, müsste eigentlich anschließend noch eine Prüfung (z.B. über Assertions) eingebaut werden, ob beispielsweise der User erfolgreich eingeloggt werden konnte.
Der Selenium WebDriver wird also vom Client API angesprochen und ist eigentlich selbst eine API, das in mehreren Implementierungen zur Verfügung steht. Es gibt für jeden unterstützten Browser eine spezifische Implementierung des WebDriver-Interfaces, die mit seinem jeweiligen Counterpart interagieren kann. Der große Vorteil dieses API-Designs ist, dass ein Testskript, geschrieben in einer beliebigen Programmiersprache, alle verfügbaren WebDriver-Implementierungen bedienen kann. Ein einziges Testskript kann also auf allen vorgesehenen Browsern und Browserversionen ausgeführt werden (Cross Browser Testing).
Lokal testen
Selenium unterstützt neben der ferngesteuerten (remote) auch die lokale Ausführung der Oberflächentests, z.B. auf dem eigenen Entwicklerrechner. Vorausgesetzt, die zu testende Anwendung ist über diesen Rechner erreichbar (ggf. auch mit einer HTTP-Authentifizierung, die unterstützt wird).
Dabei spricht das Testskript/Client API direkt mit dem Selenium WebDriver, dessen entsprechende Implementierung wiederum den lokal installierten Browser startet und ihn steuert.
Ein Selenium Server muss für lokal ausgeführte Tests nicht mehr aufgesetzt werden (im Vergleich zu Version 1 von Selenium, wo das Selenium RC-Modul, den Browser fernsteuerte und, egal ob lokal oder remote, nur über einen laufenden Selenium Server angesprochen wetrden konnte).
Remote, verteilt und parallelisiert testen
Noch spannender wird die Sache jedoch, wenn eine verteilte und parallelisierte Lösung für die Testautomatisierung angestrebt wird. Im zweiten Teil dieser Artikelreihe gehen wir deshalb auf das interessanteste Feature von Selenium ein: dem Selenium Grid.
2 Kommentare
Pingback: Automatisierung von fachlichen UI-Tests mit Selenium (2/2) | The Cattle Crew Blog
Pingback: Testcontainers – Unleash Your (Unit) Tests Using Docker (2/3) | The Cattle Crew Blog