Wie man mit dem Testframework SikuliX eine GUI testet möchte ich in diesem Tutorial beschreiben.
Die Webseite zum Testframework SikuliX ist komplett in Englisch gehalten.
Des Weiteren ist diese Seite nicht wirklich übersichtlich und vieles erschließt sich nicht von selbst, daher soll dieses Tutorial einen geordneten Überblick über das Testframework liefern.
Das Hauptaugenmerk soll jedoch auf die Erstellung von Testfällen in Oracle Java stehen.
Ab dem 22.08.2018 ist die neue Version 1.4 zum Download unter https://raiman.github.io/SikuliX1/downloads.html erhältlich.
Der Entwickler verspricht mit dieser neuen Version eine deutliche Verbesserung der Erkennung von Bildern.
Testanwendung
In diesem Tutorial verwende ich eine einfache Oracle Java Swing Anwendung, welche ich im Kapitel Downloads zum Herunterladen anbieten möchte.
Die Anwendung verfügt über:
- einen Titel,
- mehrere Schaltflächen,
- wobei sich zwei Schaltflächen wiederholen,
- mehrere Textfelder
- zwei Eingabefelder, und
- eine Schaltfläche “OK”
Des Weiteren verfügt das Fenster über die Schaltflächen
- minimieren,
- maximieren,
- schließen, sowie
- dem Kontextmenü des Icons
Erstellen von Testfälle
Einrichtung
Als Erstes muss das JavaArchiv “sikulixapi.jar” heruntergeladen und in das Projekt integriert werden.
Build Tools
Wenn ein Buildmanagement wie Apache Maven, Gradle oder ähnliches verwendet wird, so findet man unter https://www.mvnrepository.com/search?q=sikulix die benötigten Abhängigkeiten. Jedoch sind diese nicht auf den aktuell Stand, somit muss man ein lokales Repository anlegen und dort die JAR Datei ablegen.
Apache Maven Projekt einrichten
Wie man Apache Maven einrichtet habe ich im gleichnamigen Tutorial Maven: Einrichten von Apache Maven bereits erläutert. In diesem Kapitel möchte ich darauf eingehen wie eine lokale JAR Datei in Apache Maven eingebunden wird.
Ablage der JAR Datei “sikulixapi.jar”
Es ist von Vorteil die JAR Datei in das Projekt abzulegen.
Man kann diese auch extern ablegen, jedoch muss man dann bei einem exportieren des Projektes daran denken alle benötigten Ressourcen zusammenzutragen.
Hat man also nun die lokale Datei im Projekt (wie in der Grafik ersichtlich) abgelegt, so muss man in der Datei “pom.xml” folgenden Eintrag ergänzen:
<dependency> <groupId>com</groupId> <artifactId>sikulixapi</artifactId> <version>1.4</version> <scope>system</scope> <systemPath>${project.basedir}/repository/com/sikulixapi/1.4/sikulixapi.jar</systemPath> </dependency>
Nachdem die Änderungen vorgenommen wurde, muss der Buildprozess mit “mvn install” einmal angestoßen werden. Danach ist dann SikuliX im Projekt verwendbar.
Einbinden von JUnit5
Zusätzlich möchte ich JUnit5 nutzen, um die Testfälle zu gruppieren.
Das Testframework JUnit5 wird als Dependency in der Datei “pom.xml” eingebunden.
<dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-engine</artifactId> <version>5.3.0-RC1</version> <scope>test</scope> </dependency>
Eclipse Projekt
Der einfachste Weg ist wohl ein Eclipse Projekt, in diesem kann man dann die JAR Datei über das Kontextmenü “Build Path” -> “Add to Build Path” hinzufügen.
Java & JUnit
Nachdem die Einrichtung erfolgt ist können die ersten Testfälle erstellt worden, hier kann man entweder JUnit verwenden oder einfachen Java Code. Ich empfehle die Verwendung von JUnit.
Mit der neuen JUnit5 Version kann man mit Annotations-Testfälle gruppieren dieses hat den Vorteil das man ein Set erstellt und dann je nach Belieben ausführen kann.
Das gesamte Eclipse Projekt findest du auch bequem zum Download am Ende dieses Tutorials.
Annotations zum Gruppieren von Testfällen
Ich erstelle mir hier 2 Annotations welche ich für die nachfolgenden Testfälle verwenden möchte.
Als Erstes eine Annotation für alle Testfälle, dieses erlaubt mit nur einem Tag alle Testfälle auszuwählen.
package de.draegerit.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.junit.jupiter.api.Tag; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Tag("full") public @interface Full { //Bleibt leer }
Es soll einmal ein Set geben, welches nur sehr wenige Testfälle ausführt, dieses kann Bsp. nützlichlich sein, wenn man eine Änderung am Code durchgeführt hat und nur den einen Teil der Software testen möchte.
package de.draegerit.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.junit.jupiter.api.Tag; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Tag("lowlevel") @Full public @interface LowLevel { //Bleibt leer }
Nun noch ein Testset mit den Testfällen welche ausgeführt werden sollen wenn Bsp. Weitreichende Änderungen durchgeführt wurden.
package de.draegerit.util; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.junit.jupiter.api.Tag; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Tag("basic") @Full public @interface Basic { //Bleibt leer }
Bildausschnitte für die Testfälle erzeugen
Das Testframework SikuliX arbeitet mit Testausschnitten, d.h. es wird eine Region auf einer Anwendung als Bildschirmfoto aufgenommen und mit diesem Bild wird eine Aktion ausgeführt.
Greenshot
Die Bildschirmausschnitte erzeuge ich mit der Anwendung Greenshot.
Die Anwendung kann man kostenlos auf der Seite http://getgreenshot.org/downloads/ für Microsoft Windows heruntergeladen werden. Wenn du einen Mac hast, dann bekommst du diese Software für 1.99 $. (“Ein Schelm, wer Böses dabei denkt.”)
Nach dem Download und der Installation kann man mit der Schaltfläche “druck” auf der Tastatur Greenshot bequem starten.
Sollte man ein Video gestartet haben, so wird dieses Bild eingefroren (läuft aber im Hintergrund weiter).
Bildformat und Größe
Die Anwendung Greenshot, bietet die Möglichkeit, die Bilder in den folgen Formaten zu speichern:
- *.bmp
- *.gif
- *.jpg
- *.png
- *.tiff
- *.ico
Von diesen genannten Bildformaten unterstützt das Testframework SikuliX jedoch “nur” *.jpg und *.png.
Die Größe des Ausschnittes sollte so klein wie möglich, jedoch auch Redundanz frei sein.
Das heißt, im Idealfall sollte der Bildausschnitt, genau nur einmal auf dem Monitor präsent sein.
Wenn man eine klick, Aktion mit hilfe eines Bildausschnittes erzeugen möchte so wird die Mitte des Bildes verwendet.
Diesen Umstand muss man beim Erstellen der Bilder beachten.
Die IDE zum Testframework SikuliX biete hier eine Hilfe bei dem Erzeugen der Bildausschnitte an und zeigt ein Kreuz im Bild an, so erkennt man wo genau die Aktion ausgeführt wird. Dieses kann zum Beispiel bei Checkboxen eine sehr gute Hilfe sein.
Multimonitor-Betrieb
Für Entwickler ist es heute üblich, nicht nur einen Monitor zu verwenden, sondern min. 2 (auf arbeit habe ich sogar 3 Stück angeschlossen).
Das Testframework SikuliX kann in der aktuellen Version 1.4 nur auf dem Monitor 1 arbeiten, d.h. Anwendungen welche auf dem 2ten bis nten Monitor laufen können nicht verarbeitet werden.
Testfälle
Testfall #1 – prüfen ob die Anwendung läuft
Als Erstes prüfen wir, ob die Anwendung läuft. Dazu erstelle ich mir einen Bildausschnitt von der Titelleiste der Anwendung.
ABER Achtung, es muss hier unterschieden werden, ob die Anwendung gerade den Fokus hat oder nicht. Denn wenn die Anwendung nicht den Fokus hat, sind die Elemente (Icon, Text und Schaltflächen) grau.
Ich prüfe in diesem Testfall ob, der oben gezeigt Bildausschnitt auf dem Monitor zu finden ist.
Wenn sich dieser Bildausschnitt nicht auf dem Bildschirm befindet, so wird eine FindFailed Exception geworfen.
@Basic public class TestCase1 { private static Screen s; @BeforeAll public static void setUp() { s = new Screen(); } @Test public void test1ApplicationShouldBeStarted() { Executable exec = () -> { s.click("images/dialog_title_click.png"); }; assertDoesNotThrow(exec); } }
Was passiert hier?
In der Methode “setUp”, welche in diesem Testfall mit der Annotation “@BeforeAll” anotiert wurde, wird das Objekt “Screen” erstellt. Mit diesem Objekt kann man nun verschiedene weitere Methoden aufrufen, welche auf dem Monitor ausgeführt werden sollen.
Die Methode “click(<<String>>);” erwartet einen Dateinamen, diese Zieldatei muss ein Bild sein. Dieses Bild wird nun auf dem aktuellen Monitor gesucht und angeklickt.
Wenn der Bildausschnitt nicht gefunden wurde, so wird eine FindFailedException geworfen und der Testfall abgebrochen. In meinem Fall teste ich durch “assertDoesNotThrow” das die Exception nicht geworfen wurde.
Testfall #2 – einen Bereich hervorheben
Man kann einen Bereich suchen und dann einen Rahmen mit einer beliebigen Farbe drumherum zeichnen.
//Schaltfläche "0" suchen und mit einem roten Rahmen markieren. s.find("images/btn_0.png").highlight(2, "#FF1616");
Der erste Parameter der Methode “highlight” ist die Dauer der Anzeige des Rahmens, d.h. wie lange der Rahmen sichtbar ist.
Der zweite Parameter ist der Farbwert, in diesem Beispiel habe ich ein HEX Wert für die Farbe Rot gewählt. Statt eines Hexadezimalen Wertes für die Farbe kann man auch das Wort auf Englisch benutzen wie Bsp. “blue”, “red” oder “green”.
Wenn man einen bestimmten Farbwert sucht, so kann man die Seite http://www.color-hex.com nutzen. Dort findet man immer den Hex Wert und den RGB Wert zu einer Farbe.
private static Screen s; private String[] files = { "images/okBtn/btn_ok.png", "images/okBtn/btn_ok.jpg"}; private String[] colors = { "red", "green" }; @BeforeAll public static void setUp() { s = new Screen(); } @Test public void testFiletypes() throws FindFailed { for (int i = 0; i < files.length; i++) { Match find = s.find(files[i]); find.highlight(2, colors[i]); } }
Testfall #3 – eine Schaltfläche anklicken
Nachdem die Anwendung gefunden wurde, möchten wir nun eine Aktion auf dieser ausführen. Dazu klicke ich die Schaltfläche “0”.
s.click("images/btn_0.png");
Der Methode “click” wird wiederum ein String übergeben, welcher den Dateinamen zu einem Bild enthält.
Testfall #4 – ein Textfeld befüllen
Die Testanwendung enthält die Felder für “Vorname” & “Name” sowie die Schaltfläche “OK”.
Erzeugen wir nun einen Testfall in welchem wir den Vornamen “Max” sowie den Nachnamen “Mustermann” eintragen und die Schaltfläche “OK” betätigen.
Nachdem die Schaltfläche “OK” betätigt wurde, muss ein Dialog angezeigt werden, in welchem diese Daten angezeigt werden.
@Test public void testInputFirstnameLastname() { Executable exec = () -> { s.click("images/input_vorname.png"); s.type("Max"); s.click("images/input_name.png"); s.type("Mustermann"); s.click("images/okBtn/btn_ok.png"); Match find = s.find("images/dialog_aktion_vorname_name.png"); find.highlight(6, "red"); }; assertDoesNotThrow(exec); }
Ergebnis
Testfall #5 – eine doppelt vorhandenes Element Testen
In meiner Testanwendung ist die Schaltfläche “1” doppelt vorhanden.
Wenn man nun den Bildausschnitt um die Schaltfläche erstellt dann findet, SikuliX diesen ausschnitt zweimal.
In diesem Beispiel habe ich nun alle gefundenen Elemente mit einem grünen Rahmen, für 3 Sekunden markiert.
Resourcen zum Download
Testanwendung
Eclipse Projekt
[wpdm_package id=’6950′]