Cypress ist ein junges Open-Source-Test-Framework für Web-basierte, grafische Benutzeroberflächen. Cypress-Tests werden in JavaScript geschrieben und orientieren sich, wie auch bei Selenium-basierten Technologien üblich, am Document Object Model (DOM) des HTML einer Web-Anwendung.
Im Vergleich zum bekannten Vorfahren Selenium bietet Cypress viele Verbesserungen, die zu erhöhter Stabilität, Zuverlässigkeit sowie Laufzeit- und Entwicklungs-Geschwindigkeit führen. Die Vorteile des Youngstar und warum sich der Einsatz von Cypress lohnt, wollen wir uns im Verlauf dieses Artikels einmal näher anschauen.
Spitze Pyramiden: UI- statt Ende-zu-Ende-Tests
Bevor man motiviert die ersten Cypress-Tests schreibt, sollte entschieden werden, was überhaupt getestet wird. Vor dem Start sollte man sich überlegen, ob lediglich die Oberfläche oder das ganze System (Ende-zu-Ende bzw. E2E) getestet werden soll. In der klassischen Pyramide koexistieren beide Arten von Tests. Dabei ist es gängig, wenige jedoch geschäftskritische E2E-Tests und viele detailtiefe Oberflächentests, losgelöst vom Backend, zu nutzen. Auch der Namensgeber des Frameworks, die Zypresse, bestätigt diesen Ansatz durch ihr Erscheinungsbild: spitz zulaufende Test-Pyramiden stehen für viele Unit-, UI- & Integrationstests sowie wenige E2E-Tests.
Warum sollten nicht alle Testfälle als E2E-Test gegen das ganze System gerichtet werden? Das erfahren Entwicklungsteams oft schmerzhaft. E2E-Tests sind langsamer, da von der zu testenden Oberfläche Anfragen an „echte“ Backends gestellt werden. Auch sind sie instabiler, da Tests von der Datenhaltung der Backends abhängig sind. In echten Umgebungen sind Daten dynamisch – eine schwierige Voraussetzung für automatisierte Tests. Daten ändern sich durch Synchronisationen aus Fremdsystemen, manuelle Interaktionen von Nutzern und werden zusätzlich noch mit einer abgeschwächten Konsistenz (Eventual Consistency) den Konsumenten zur Verfügung gestellt. Um darauf wiederum im Test zu reagieren, werden oft Warte- und Wiederholungs-Mechanismen eingebaut, die die Komplexität und den Frust im Team erhöhen. Das alles hat zur Folge, dass E2E-Tests selten deterministische Ergebnisse liefern, sondern häufiger fehlschlagen und damit den Entwicklungsprozess behindern können. E2E-Tests haben ihre Berechtigung, sind jedoch schlichtweg teurer.
Reine Oberflächentests, in denen die Backend-Anfragen durch kontrollierbare Daten ersetzt werden, eignen sich besser, um jede Funktionalität im Detail abzutesten. Sie können testgetrieben mit dem UI entwickelt werden und sind eine günstige Investition in eine gut getestete Codebasis.
Netzwerktraffic mit Cypress unter Kontrolle bringen
In reinen Oberflächentests profitiert man von der Kontrolle über Daten, die die Serverseite liefert. Cypress glänzt hier auf voller Linie, da dessen im nächsten Bild sichtbare Architektur dies vorteilhaft berücksichtigt.
Die Architektur während eines Tests besteht aus einem Node.js-Prozess (die „Serverseite“) und einem laufenden Browser. Im von Cypress instrumentalisierten Browser wird eine Seite aufgerufen, die die getestete Applikation wie auch ein Cypress-UI als iFrame einbettet. Der Testcode wird ebenfalls im Cypress-iFrame ausgeführt, sodass Testcode und Anwendungscode im gleichen Browser-Tab und somit auch im gleichen JavaScript-Loop laufen. Der Testcode kommuniziert über WebSockets mit dem Node-Prozess. Der Node-Prozess agiert als Proxy für jede HTTP-Anfrage aus dem Browser und kann sogar Shell-Kommandos ausführen .
Der Schlüssel zur Kontrolle des Netzwerktraffic liegt im Proxy. HTTP-Anfragen können aufgezeichnet werden. Somit kann im Test auf spezifische Anfragen gewartet werden, damit der Test erst fortfährt, wenn deren Antwort empfangen wurde. HTTP-Antworten können mit Fixtures überschrieben werden, anstatt die Anfragen an das echte Ziel zu senden und deren Antwort abzuwarten. Somit können wir die Antwort einer Anfrage fälschen, ohne die Anwendung gegen einen anderen Host konfigurieren zu müssen – das übernimmt alles der Proxy, wenn wir ihn über die richtigen Cypress-Befehle im Test dazu bringen.
Außer HTTP-Anfragen können auch die lokale Zeit und sogar JavaScript-Objekte während der Laufzeit überschrieben (Stubs) oder observiert (Spies) werden. Das hilft, wenn von der Uhrzeit abhängige Teile der Anwendung deterministisch getestet werden sollen. Durch das Überschreiben von JavaScript-Objekten können wir der Anwendung sogar “vorspielen”, dass ein Benutzer eingeloggt ist, um uns auf die zu testende Kernfunktion konzentrieren zu können.
Ohne Selenium WebDriver für das moderne Web
Cypress trumpft, unabhängig von der Art des Testens, mit hoher Stabilität und Zuverlässigkeit im verglichen mit Selenium-basierten Tests. Selenium-Nutzer kennen die oft willkürliche und frustrierende „Flakiness“ von DOM-Assertions, welche zu fehlschlagenden Tests führt. Cypress baut nicht auf Selenium WebDriver oder ähnlichem auf, sondern wurde grundlegend neu für die Prinzipien heutiger Web-Anwendungen konzipiert und gebaut. Stark JavaScript-lastige Seiten und Single-Page-Applications (SPA) laden über HTTP-Anfragen und WebSockets kontinuierlich Ressourcen nach, führen DOM-Änderungen durch und sind stets in Bewegung.
Diese Dynamik lässt sich mit üblichen, statischen „waits“ und „sleeps“ schwer testen. Stattdessen wartet Cypress intelligent auf Kommandos, das Vorhandensein und sogar Animationen von DOM-Elementen und lässt „waits“ auf erwarteten HTTP-Requests definieren. Testing Code wird sauberer, lesbarer und weniger komplex. Die Ausführungsdauer reduziert sich auf die Zeit, die benötigt wird, um die Anwendung durch alle Status zu führen. Sie wird nicht mehr länger durch „sleeps“ und „waits“ verlangsamt.
Die Veränderungen der Oberfläche werden von Cypress zudem als DOM Snapshots aufgezeichnet. Somit kann auch nach der Ausführung des Tests im grafischen, interaktiven Modus abgespult werden, wie sich die Anwendung über den Test hinweg verändert hat. Zusätzlich können Videos der ganzen Ausführung sowie Screenshots bei Fehlschlägen aufgezeichnet werden, um bspw. Fehler während der Ausführung in einer Continuous Integration Pipeline untersuchen zu können. Sogar visuelle Regressionstests mit Cypress sind möglich. Hierbei wird das angestrebte Erscheinungsbild der Anwendung als Spezifikation gespeichert und das Ergebnis nach der Testausführung mit der Erwartung verglichen.
Flora und Fauna – Erweiterbarkeit von Cypress
Zypressen prägen das Landschaftsbild der schönen Toskana, kommen aber keinesfalls alleine vor. So entwickelt sich auch das florierende Ökosystem rund um Cypress in alle Richtungen weiter. Das Framework ist durch Custom Commands , Plugins und Events durch die Entwickler*innen erweiterbar.
Für viele Aufgabenstellungen, wie Login in E2E-Tests, Component Testing, File Uploads, Drag-and-Drop und viele mehr existieren bereits gute Cypress-Plugins . Ein gutes Beispiel für die Erweiterbarkeit von Cypress liefert auch der Artikel „BDD und End-to-End-Tests – Cypress mit Cucumber verbinden “ meines Kollegen Holger Grosse-Plankermann. Hiermit wird das Schreiben von Cypress-Testfällen in Gherkin-Syntax ermöglicht.
Cypress Custom Commands bieten sich auch an, um oft verwendeten Code (wie das Präparieren der Antwort eines Identity Providers) zu mocken, oder um fachliche Aktionen wie das Navigieren auf eine bestimmten Seite zu extrahieren.
Zum Ökosystem gehört auch der Cypress.io Dashboard-Service , mit Hilfe dessen Testergebnisse online aufgezeichnet, inspiziert und im Team sichtbar gemacht werden können. Er zählt zwar zum kostenpflichtigen Teil von Cypress.io , bietet jedoch auch ein Free Tier für kleine Projekte. Leider ist die Nutzung des Dashboard-Services für die Parallelisierung von Tests nötig, da ein serverseitiger Speicher benötigt wird. Dieser sammelt Metadaten über die Testausführungen, um eine sinnvolle Verteilung der Testfälle auf mehrere Worker zu gewährleisten. Um einen alternativen, unabhängigen Dashboard Service zur Verfügung zu stellen, kümmert sich ein Projekt namens „Sorry Cypress “.
Fazit
Cypress löst zweifelsfrei viele Probleme bisheriger Web-basierter Oberflächentests und hat für viele Entwickler*innen den Zahn der Zeit getroffen. In vielen Teams, die mit digitaler Produktentwicklung arbeiten, wird Oberflächen- und E2E-Tests noch nicht genügend Priorität eingeräumt. Das automatisierte Testing von UIs wird zwar theoretisch als vielversprechend angesehen, jedoch oft als komplex, zeitintensiv und unrobust wahrgenommen. Cypress befindet sich auf dem Weg, dieses Ansehen mit steigender Bekanntheit zu wenden und bringt positive Auswirkungen, wo es schon genutzt wird.
Für Teams, die alte Browser wie den Internet Explorer unterstützen müssen, stellt der Browser-Support von ausschließlich modernen Browsern ein Hindernis dar. Mittlerweile werden Chrome, Chromium, Firefox, Edge und Electron unterstützt – insofern hat sich Cypress positiv weiterentwickelt.
Auch die nur mit dem Dashboard-Service nutzbare Test-Parallelisierung wird häufig bemängelt. Jedoch schafft „Sorry Cypress“ Abhilfe, wenn man sich mit dem Betrieb eines eigenen Services arrangieren kann. Doch auch diese Idee hat sich kommerziell entwickelt, sodass es „Sorry Cypress“ mittlerweile auch als kostenpflichtig bereitgestellten Cloud Service gibt.
Zusammenfassend kann Cypress für Oberfläche- und Ende-zu-Ende-Tests uneingeschränkt empfohlen werden, wenn man auf automatisierte Tests in veralteten Browsern verzichten kann.
Weitere Beiträge
von Jonas Verhoelen
Dein Job bei codecentric?
Jobs
Agile Developer und Consultant (w/d/m)
Alle Standorte
Weitere Artikel in diesem Themenbereich
Entdecke spannende weiterführende Themen und lass dich von der codecentric Welt inspirieren.
Gemeinsam bessere Projekte umsetzen.
Wir helfen deinem Unternehmen.
Du stehst vor einer großen IT-Herausforderung? Wir sorgen für eine maßgeschneiderte Unterstützung. Informiere dich jetzt.
Hilf uns, noch besser zu werden.
Wir sind immer auf der Suche nach neuen Talenten. Auch für dich ist die passende Stelle dabei.
Blog-Autor*in
Jonas Verhoelen
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.
Du hast noch Fragen zu diesem Thema? Dann sprich mich einfach an.