Ich hatte schon einige Jahre als Selenium Engineer in einem Projekt gearbeitet, als das agile Team die Entscheidung getroffen hatte, zukünftig neue Module in Kotlin zu entwickeln, unter anderem auch die automatisierten Tests. Nach zwei Jahren erfolgreichem Einsatz von Selenium (mit Cucumber) in Kotlin möchte ich meine persönlichen Highlights hier erläutern, ohne dabei Anspruch auf Vollständigkeit zu erheben. Ich möchte den einen oder anderen Leser ermutigen, sich auf das Experiment einzulassen, denn wenn man es gewagt hat, möchte man nicht mehr zu Java zurückkehren, also Vorsicht!
Warum Kotlin
Wirft man einen Blick auf Analysen von 2019 und 2020 ([PYPL], … ), scheint Kotlin keinen besonders großen Marktanteil zu haben. Jedoch erscheint Kotlin immer öfters in Rankings für die „bevorzugte“ Programmiersprache oder als bei Jobinterviews nachgefragte Sprache [IEEE].
Warum überhaupt Kotlin für ein Selenium-Framework verwenden, warum nicht bei Java bleiben? Hier habe ich die meiste Erfahrung, und „cool“ und „neu“ waren für mich keine Argumente, um die notwendige Testautomation für ein Projekt in Kotlin zu wagen.
Aus rein technischer Sicht ohne Rücksicht auf Selenium sind in der offiziellen Dokumentation [Kot] beispielsweise die in Tabelle 1 zusammengefassten Unterschiede zwischen Kotlin und Java aufgelistet.
Tabelle 1: Comparison to Java Programming Language, siehe [Com]
Ich möchte hier jetzt nicht allgemeine Dinge beleuchten, die für bessere Codequalität sorgen oder der Fehlervermeidung dienen, wie Null-safety, vielmehr, was hat mir als Entwickler der Testautomation gefallen und ein gewisses „Aha“-Erlebnis gebracht. Unter anderem haben folgende Aspekte entscheidend dazu beigetragen, den Schritt zu wagen, das Projekt mit Kotlin zu automatisieren.
Coroutines
Coroutines sind eine einfache und effektive Möglichkeit, um asynchrone Abläufe zu realisieren. Ein wichtiger Aspekt meiner Arbeit ist es, gut lesbare und technisch einfache Selenium-Testfälle zu schreiben. Man kann Coroutines beispielsweise zur Zeitmessung und für Timeouts einsetzen.
Zeitmessungen einzelner Operationen
Bei der Auswertung eines Selenium-Skripts und der Suche nach Optimierung stellt sich oft die Frage, warum benötigt die Ausführung so lange, wo steckt das meiste Potenzial für eine Optimierung.
Während Zeitmessungen in Java etwas Handwerk benötigen, ist dies mithilfe der Coroutine measureTime (bzw. measure TimeMillis, …) sehr einfach und mit wenig Code umsetzbar. Hierbei ist jetzt außer Acht gelassen, dass diese Zeitmessungen den Overhead von Selenium nicht berücksichtigen und „mitgemessen“ werden.
Das Beispiel in Listing 1 misst die Zeit aller Anweisungen in Millisekunden, die innerhalb der Coroutine ausgeführt werden. Im „also“- Block wird dann, falls die Anweisungen mehr als 3000 ms benötigen, ein Eintrag im Log gemacht.
Listing 1: Zeitmessung
Timeout
Auch wenn die ExpectedConditions sehr gute Möglichkeiten bieten, um stabile und effiziente Wartestrategien zu verwirklichen, gibt es auch Situationen, die mit withTimeout gut gelöst werden können. Vor allem dann, wenn zum Beispiel die Bedingung nicht über ein WebElement abgefragt werden kann (siehe Listing 2).
Listing 2: Timeout
Das Backend wird abgefragt, ob noch Daten angeliefert werden, falls ja, dann wird die Anfrage nach 300 ms wiederholt.
Extensions
Erfahrene Selenium-Entwickler haben sicher schon mal das Problem gehabt, dass einzelne Elemente nicht mit allen Standardmethoden, die der WebDriver für WebElemente anbietet, angesteuert werden können. Hier können die Extensions von Kotlin ihre Stärke ausspielen.
In Java hat man zwei Möglichkeiten. Variante A: ein Wrapper-Objekt zu erzeugen.
Das geht meist nur mit großem Aufwand, da eventuell alle Objektinstanzierungen geändert werden müssen. Zum Beispiel mit einer Ableitung von dem Objekt WebElement.
Variante B: Es kann auch eine Utility-Klasse erstellt werden, die dann Methoden zum Beispiel für WebElemente zur Verfügung stellt:
clearInput(textBox)
Kotlin bietet dagegen mit der Extension eine einfache Möglichkeit, um vorhandene Objekte wie zum Beispiel das WebElement-Objekt einfach mit einer Funktion zu erweitern.
Angenommen, die clear()
-Methode funktioniert nicht wie gewünscht und löscht den Text nicht aus einem Textfeld. Im Beispiel in Listing 3, das aus einem vergangenen Projekt stammt, wird bei Verwendung von Firefox ein gewöhnliches clear
aufgerufen. Und in allen anderen Fällen wird der vorhandene Text mittels Tastenkombination Strg+A (markiert den Text im Textfeld) und „Entf“ gelöscht.
Diese Methode kann an allen Stellen im Programmcode verwendet werden und am restlichen Code muss nichts verändert werden
Listing 3: Extensions
Data classes
Oft werden in Selenium-Skripts zusammenhängende Daten verwendet, hier bieten Data classes [Lei] in Kotlin eine gute Möglichkeit, um diese zu verwalten. Gerade in Verbindung mit Selenium und eventuell in Kombination mit Cucumber bieten Data classes eine effektive und sehr schlanke Möglichkeit, um Testdaten beziehungsweise Testdatenobjekte zu speichern:
data class Person(var name:
String, var surname: String,
var id: String)
Diese Klasse in Java mit all den Funktionen abzubilden, würde gute 50 Codezeilen benötigen im Vergleich zu einer Codezeile in Kotlin. Mit der Definition der Data-Klasse können Personen-(Test)daten erzeugt und kopiert werden (mit gleichzeitiger Datenmanipulation):
val person = Person('Max',
'Mustermann', '1001')
val personMaximilian = person.
copy(name='Maximilian')
Die erste Codezeile erzeugt ein Personenobjekt mit den angegebenen Attributen, die zweite weist der Variablen personMaximilian
eine Kopie von person
zu, jedoch wird das Attribut name
auf „Maximilian“ geändert.
Zusammenfassung
Selenium kann ohne großen Aufwand mit Kotlin statt Java programmiert werden. Die Vorteile liegen klar auf der Hand: Kotlin ist eine um ca. 20 Prozent schlankere Sprache als Java, sprich: Es kann mit weniger Code die gleiche Funktionalität programmiert werden. Durch die hohe Kompatibilität zu Java muss man keine Scheu vor dem Umstieg haben. Aus eigener Erfahrung kann ich es nur empfehlen. Der Lerneffekt tritt sehr rasch ein und die Online-Dokumentation ist gut und ausführlich und für Java-Umsteiger schnell zu erlernen.
Der Einsatz mit Selenium und optional Cucumber hat sich aus subjektiver Sicht in der Praxis bewährt und zu deutlich weniger Codezeilen und somit auch zu besser zu wartendem Testcode geführt.
Weitere Informationen
[Bos18] S. Bose u. a., A comperative Study: Java vs Kotlin Programming in Android Application Development, in: Int. J. of Advanced Research in Computer Science, Mai/Juni, 2018, siehe:
http://dx.doi.org/10.26483/ijarcs.v9i3.5978
[Com] Comparison to Java Programming Language, siehe:
https://kotlinlang.org/docs/reference/comparison-to-java.html
[IEEE]
https://spectrum.ieee.org/static/interactive-the-top-programming-languages-2020
[Lei] A. Leiva, Data Classes in Kotlin: save a good bunch of lines of code (KAD 10), siehe:
https://antonioleiva.com/data-classes-kotlin/#:~:text=The%20advantage%20of%20using%20data,amount%20of%20self%2Dgenerated%20 code.&text=The%20properties%20declared%20in%20the, in%20addition%20to%20the%20constructor
[PYPL] PopularitY of Programming Language, siehe:
https://pypl.github.io/PYPL.html
[Wiki]
https://de.wikipedia.org/wiki/Kotlin_(Programmiersprache)