3.6. Erstellen von Tests

Das Erstellen von GUI-Tests mit checkerberry web wird am Beispiel einer einfachen Login-Seite verdeutlicht. Die folgende Grafik stellt die zu testende Login-Seite dar.

Abbildung 3.6. Login-Maske

Login-Maske


Das zu testende HTML-Formular verfügt im Wesentlichen über drei relevante Komponenten: ein Eingabefeld für den Namen, ein Eingabefeld für das Passwort und einen Login-Button zum Absenden des Requests. Die zugehörige HTML-Datei sieht wie folgt aus:

Beispiel 3.10. login.html

<html>
  <form action="/login" method="get">
    <table>
      <tr>
        <td>User</td>
        <td><input name="user" id="userId" type="text"></td>
      </tr>
      <tr>
        <td>Password</td>
        <td><input name="password" id="passwordId" type="password"></td>
      </tr>
      <tr>
        <td>&nbsp;</td>
        <td><input id="loginId" value="Login" type="submit"></td>
      </tr>
    </table>
  </form>
</html>


Bevor der eigentliche Test implementiert werden kann, muss ein Modell für die zu testende Webseite erstellt werden. Das Modell enthält Getter-Methoden für alle Komponenten der Webseite, die durch den Test angesprochen werden sollen. Die Methoden liefern eine Instanz der Klasse RemoteControlComponent zurück. Des Weiteren enthält das Modell fachliche Methoden, die in verschiedenen Tests wiederverwendet werden können. Weitere Details zum Modellansatz finden sie in Abschnitt 3.7, „Modellansatz“.

Das folgende Beispiel enthält das Modell für die Login-Seite.

Beispiel 3.11. LoginPage.java

public class LoginPage extends AbstractRemoteControlPage {

  // Konstuktor mit dem ContextProvider.
  public LoginPage(ContextProvider contextProvider) {
    super(contextProvider);
  }

  // Fernsteuerung für eine HTML-Komponente, das User-Id-Feld,
  // zurückliefern
  public RemoteControlComponent getUserTextField() {
    // Für die Erzeugung wird nur die HTML-ID benötigt.
    return createComponentProxy("userId");
  }

  // Fernsteuerung für eine HTML-Komponente, das Passwort-Feld,
  // zurückliefern
  public RemoteControlComponent getPasswordTextField() {
    // Für die Erzeugung wird nur die HTML-ID benötigt.
    return createComponentProxy("passwordId");
  }

  // Fernsteuerung für eine HTML-Komponente, den Login-Button,
  // zurückliefern
  public RemoteControlComponent getLoginButton() {
    // Für die Erzeugung wird nur die HTML-ID benötigt.
    return createComponentProxy("loginId");
  }
}


Die Klasse LoginPage erbt von der AbstractRemoteControlPage, die durch checkerberry web zur Verfügung gestellt wird. Diese Klasse stellt Basis-Funktionen für die Seite zur Verfügung. Der Konstruktor nimmt einen ContextProvider entgegen, der die Fernsteuerung (das RemoteControl-Objekt), den Kontext und die Konfiguration beinhaltet und reicht die Werte an die abstrakte Seite weiter. Das RemoteControl-Objekt bildet die Schnittstelle des Tests zu Selenium.

Für die Erstellung der Komponenten-Getter ist lediglich ein sogenannter Locator erforderlich. Ein Locator definiert, wie eine Komponente auf der Webseite eindeutig gefunden werden kann. In dem konkreten Login-Beispiel werden dazu die HTML-IDs verwendet. Mehr ist bei der Erstellung eines Modells nicht zu tun. Nachdem die Erstellung des Modells abgeschlossen ist, kann mit der Erstellung des Tests begonnen werden.

Beispiel 3.12. Test-Implementierung der Login-Seite

package de.conceptpeople.demo;

@TestUrl("http://localhost:8080/login.html")
public class LoginTest extends AbstractCheckerberryWebTest {

  public void testLogin() {

    // Erstellen des Modells für die Login-Seite. Der Test selbst
    // ist ein ContextProvider.
    LoginPage loginPage = new LoginPage(this);

    // Prüfen, dass User- und Passwort-Feld nicht vorbelegt sind.
    assertEquals("", loginPage.getUserTextField().getValue());
    assertEquals("", loginPage.getPasswordTextField().getValue());

    // Fernsteuerung für das User-Feld holen und „Homer“ eintragen.
    loginPage.getUserTextField().type("Homer");
    // Fernsteuerung für das Passwort-Feld holen und „Duff“ eintragen.
    loginPage.getPasswordTextField().type("Duff");
    // Fernsteuerung für den Login-Button holen, Button drücken und
    // warten bis die neue Seite geladen wurde.
    loginPage.getLoginButton().clickAndWaitForPage();
  }
}


Obiges Code-Beispiel zeigt eine mögliche Umsetzung. Der Test erbt von der abstrakten Klasse AbstractCheckerberryWebTest, in der die Initialisierung von checkerberry web erfolgt. In der Klasse LoginTest wird über die Annotation @TestUrl die Test-URL auf den Wert http://localhost:8080/login.html gesetzt.

Bei der Ausführung des Tests wird zunächst in der Setup-Phase eine Browser-Instanz gestartet, die die URL http://localhost:8080/login.html aufruft. In der Test-Phase wird die Methode testLogin aufgerufen. Dort wird zunächst das Modell der Login-Seite erzeugt, um auf die Komponenten der Login-Seite zugreifen zu können. Dann wird geprüft, ob die Werte der Eingabefelder für den User und das Passwort beide nicht belegt sind. Danach wird in das Eingabefeld für den User der Wert „Homer“ und als Passwort „Duff“ eingetragen. Die Eingaben werden dann über den Login-Button abgesendet.

Nach dem Test wird die Browser-Instanz in der Teardown-Phase wieder beendet.

Auf den ersten Blick überprüft der Test nur die initiale Belegung der Eingabefelder. Bei der Verwendung von checkerberry web muss man jedoch zwischen expliziten und impliziten Prüfungen unterscheiden. Der Aufruf getValue prüft zum Beispiel implizit, ob die zugehörige Komponente in der Webseite vorhanden ist und ob dort die Methode getValue aufgerufen werden kann. Sollte dies nicht der Fall sein, wird eine Exception geworfen, die die Ausführung des Tests beendet. Dieser Sachverhalt ermöglicht das einfache Happy-Path-Testen. Bei einem Happy-Path-Test werden Funktionalitäten einer Web-Anwendung mit klar definierten Eingabewerten getestet, wobei keine Fehlersituationen erwartet oder überprüft werden.

Beispiel 3.13. Test-Implementierung der Login-Seite (erweitert)

package de.conceptpeople.demo;

@TestUrl("http://localhost:8080/login.html")
public class LoginTest extends AbstractCheckerberryWebTest {

  public void testLogin() {

    // Erstellen des Modells für die Login-Seite. Der Test selbst
    // ist ein ContextProvider.
    LoginPage loginPage = new LoginPage(this);

    // Es ist sinnvoll, fachliche Aspekte in einzelne Methoden
    // auszulagern, um diese in vielen Tests wiederzuverwenden.
    loginPage.performLogin("Homer", "Duff");

    // Wenn Homer sogar der Standard-User ist:
    loginPage.performDefaultLogin();

    // Gerade bei größeren Formularen ist das Builder-Pattern
    // auch ein sinnvoller Ansatz
    loginPage.enterUser("Homer").enterPassword("Duff")
      .clickAndWaitForPage();
  }
}

Das obige Beispiel zeigt die Verwendung eines erweiterten Modells. Durch die Auslagerung von fachlichen Methoden in die Modelle, sind diese in vielen Tests wiederverwendbar. Das Builder-Pattern kann dabei sehr hilfreich sein, wenn große Formulare existieren und man immer nur eine Teilmenge der Felder eingeben möchte. Die Lesbarkeit bleibt durch die Verwendung des Builder-Patterns sehr hoch.