Zwischen Erwartung und Ergebnis: End-to-End-Tests für Web-Frontends

Seite 2: Spezialform für die Darstellung

Inhaltsverzeichnis

Visuelle Regressionstests gehen ebenfalls im Stil eines End-to-End-Tests vor, untersuchen aber vor allem die Darstellung statt der Funktionsweise. Sie weisen den visuellen Unterschied zu einer vorher definierten Vergleichsbasis aus. Ob es sich dabei um einen Fehler handelt oder nicht, müssen letztlich die Entwickler entscheiden. Ein Schwellenwert für die Differenz kann einen Hinweis geben und auf Wunsch das Fehlschlagen des Tests auslösen.

Zu den zahlreichen Paketen, die TestCafe für visuelle Regressionstests nutzen kann, gehört blink-diff: ein älteres Werkzeug von Yahoo, das immer noch verlässlich seine Dienste verrichtet. Auf GitHub findet sich eine praktische Integration für TestCafe.

Tester müssen zunächst einen Satz Screenshots für einen als korrekt angenommen Zustand der Anwendung erzeugen. Dazu bietet die Library die Funktion takeSnapshot, die sich importieren lässt und sogar TypeScript-Bindings enthält. Folgender Code erstellt für den Ansatz einen Snapshot des Bildschirms:

import { takeSnapshot } from 'testcafe-blink-diff';

fixture 'App Visual Regression Test'
    .page 'http://localhost:3000';

test("start", async t => {
  await takeSnapshot(t);
});

Zum Erstellen des korrekten Satzes dient beispielsweise folgendes Skript:

testcafe chrome:headless e2e/App.visual.test.ts -s\  e2e/screenshots --take-snapshot goldmaster

Es speichert für alle angegebenen Tests die Screenshots im angegebenen Ordner mit dem Namen "goldmaster" für den als korrekt angenommenen Zustand. Um einen Anwendungsstand auf Abweichungen zu überprüfen, erstellen Entwickler mit folgendem Aufruf einen neuen Screenshot-Satz:

testcafe chrome:headless e2e/App.visual.test.ts -s\   e2e/screenshots --take-snapshot test

Ein Skript von testcafe-blink-diff vergleicht die beiden Sätze und schlägt Alarm, wenn mindestens einer der Screenshots über dem angegebenen Schwellwert liegt. In jedem Fall generiert das Tool einen Report (s. Abb. 3), der auch den interaktiven Vergleich von Screenshots zulässt.

Übersicht der Ergebnisse des visuellen Regressionstests (Abb. 3)

Folgender Aufruf weist alle Bilder ab einem Unterschied von 0,5 Prozent als fehlerhaft aus:

testcafe-blink-diff e2e/screenshots --compare\  goldmaster:test --threshold 0.005

Für die Versionierung landet der Goldmaster-Satz der Screenshots zusammen mit den Quellen in der Versionsverwaltung. Der zum Vergleich erzeugte Satz und die generierten Reports bleiben jedoch außen vor.

Die Unterschiede sind farblich hervorgehoben (Abb. 4).

Im Anschluss können Tester sich den Unterschied zwischen Screenshots anzeigen lassen (s. Abb. 4) oder sie mit einem interaktiven Werkzeug (s. Abb. 5) nach kleinsten Abweichungen untersuchen.

End-to-End-Tests haben viele gute Eigenschaften: Sie prüfen die Anwendung auf derselben Ebene und in derselben Umgebung wie Menschen. Sie arbeiten in realen Browsern ohne Mocking.

Leider gibt es jedoch drei wesentliche Nachteile von E2E-Tests:

  1. Sie laufen immer noch langsam: Selbst die neuen Generationen der End-to-End-Tests brauchen häufig mehrere Sekunden pro Test und Browser. Dadurch verstreichen sogar für einen kleinen Testsatz in einem einzelnen Browser einige Minuten. Der Einsatz nach jeder Codeänderung ist somit unrealistisch und im äußersten Fall das Durchführen vor einem Commit realistisch. Zumindest in der CI-Pipeline lässt sich die Verzögerung durch parallele Tests verringern, da TestCafe beliebig viele Browser-Instanzen gleichzeitig erlaubt.
  2. End-to-End-Tests sind immer noch brüchig: Obwohl manuelle Waits und sporadische Fehlschläge der Vergangenheit angehören, sind End-to-End-Tests weniger stabil als Unit-Tests auf Komponenten oder gar Logik. Das liegt vor allem an der Komplexität der Aufgabe. Der Test soll echte Fehler aufdecken, ohne dass sinnvolle Abweichungen zu Fehlermeldungen führen. Beispielsweise darf ein neu übersetzter Text nicht dazu führen, dass ein Knopf nicht mehr zu finden ist. Allerdings sollte eine geänderte Übersetzung nicht automatisch zu einem Fehler führen, wenn das Layout und die Funktion der Seite nicht beeinträchtigt sind und sich lediglich der Text geändert hat. Visuelle Regressionstests lindern diese Brüchigkeit, sind aber noch zu unflexibel. Insbesondere bei Animationen und asynchronen Aktionen, bei denen der Zeitpunkt des Screenshots entscheidend ist, können sie unzuverlässig sein und Fehlalarme auslösen. Das höhlt die Glaubwürdigkeit der Tests aus, wodurch Entwickler den Ergebnissen weniger vertrauen.
  3. E2E-Tests sind zwar an menschliches Verhalten angelehnt, verhalten sich aber anders als reale Menschen: Die Auswahl der zu testenden Elemente erfolgt über Selektoren auf dem DOM und nicht über eine reale Position auf dem Bildschirm. Das führt dazu, dass die Tests durchaus unsichtbare Elemente oder zu kleine Buttons erreichen können, auf die menschliche Nutzer keinen Zugriff haben.

Sinnvolle Ergänzungen sind daher Unit-Tests, statische Checks durch Linter und Type-Checker wie TypeScript und leider weiterhin manuelle Tests. Eine statische Typisierung wie in TypeScript hat viele Vorteile. Besonders wichtig ist das frühe Aufdecken bestimmter Programmfehler. Damit kann ein statischer Typecheck oder die Nutzung eines Linters bereits als eine Form des Tests angesehen werden, die direkt beim Schreiben des Programms erfolgt. Unit-Tests sind nach wie vor sinnvoll, um gekapselte UI- oder Business-Logik zu testen. Somit werden diese Testarten in Zukunft wichtig und sinnvoll bleiben.

Komplett getestete Anwendungen können unbrauchbar sein, wenn bestimmte Bedienelemente nicht für Benutzer erreichbar sind. Keines der genannten Testverfahren widmet sich dem Thema UX. Die Frage, ob eine Anwendung überhaupt bedienbar ist, können zurzeit nur manuelle Tests beantworten. Sie sind allerdings sowohl langwierig als auch teuer, und mit zunehmender Wiederholung können sich durch Ermüdung Fehler einschleichen.