15. Nov 2021
Lesedauer 32 Min.
Höhere Qualität durch Test und Fehlersuche
Cross-Plattform-Development mit Webtechnologien (Teil 12)
Testen prüft Software auf die Erfüllung definierter Anforderungen. Dabei zielen Tests darauf ab, Software möglichst fehlerfrei in den Betrieb zu nehmen.

Bei der Entwicklung von Software-Systemen gilt die Durchführung von Tests als eines der entscheidenden Mittel zur Erhöhung der Software-Qualität. Eine wichtige Erkenntnis stellt die Tatsache dar, dass je später Tester einen Fehler entdecken, desto aufwändiger und vor allem kostspieliger gestaltet sich seine Behebung. Daher müssen die mit dem Testen verbundenen Tätigkeiten möglichst frühzeitig im Prozess der Software-Entwicklung stattfinden.Beispielsweise verlangt die Methode der testgetriebenen Entwicklung (Test-Driven Development/TDD) eine Spezifikation und sogar Implementierung von Softwaretests möglichst schon vor beziehungsweise parallel zu den zu testenden Komponenten. Allerdings kann aus diesem Ansatz ein sehr großer Aufwand resultieren, so dass man diesen in der Praxis mit den damit verbundenen Kosten abwägen muss. Empfehlenswert ist es, sich dabei an einer Bewertung der zu unterstützenden Geschäftsprozesse oder an einem noch näher festzulegenden Detaillierungsgrad zu orientieren.
Iterative und inkrementelle Testdurchführung
In der Praxis findet, abhängig von der Bedeutung und der erwarteten Lebensdauer der Software im Unternehmen, die testgetriebene Entwicklung in unterschiedlich starker Ausprägung statt. Für die Unterstützung der Durchführung von Tests gilt der Einsatz von Werkzeugen als unverzichtbar. Dabei nimmt insbesondere die Automatisierung von Tests mit geeigneten Tools eine wichtige Rolle ein. Die Ausführung von Tests soll möglichst ohne manuellen Eingriff ablaufen, eine Protokollierung und Auswertung der Testergebnisse automatisch erfolgen.Agilität im Entwicklungsprozess und beim Testen
Agilität als Merkmal für flexibles und proaktives Arbeiten hilft sowohl im Entwicklungsprozess als auch beim Testen, die <br/>Anwendung auf die Kundenanforderungen zu fokussieren.
Eine hohe Qualität eines Software-Produkts setzt eine stetige und kontinuierliche Zusammenarbeit aller im Entwicklungsprozess beteiligten Rollen voraus. Mitarbeiter der Fachabteilung, Analytiker, Architekten, Programmierer, Tester und Qualitätsmanager müssen sich gegenseitig unterstützen. Will man eine stabile und zuverlässige Software mit wenig Fehlern ausliefern, so dürfen die Aufgaben der Entwicklung und Tests nicht voneinander getrennt, sondern müssen parallel und ineinander verzahnt ablaufen. Idealerweise übernehmen alle beteiligten Rollen auch Aufgaben, die traditionell im klassischen Entwicklungsprozess üblicherweise einem Tester zugeordnet wurden.
Hohe Testabdeckung und eine effiziente Testdurchführung
Es gilt, das gesamte Team mit den Arbeitspaketen auf das gemeinsame Ziel einer hohen Qualität des Software-Produkts auszurichten. Dazu benötigt man eine hohe Testabdeckung und eine effiziente Testdurchführung. Zusätzlich muss man ein ausgeglichenes Gleichgewicht zwischen möglichst wenig manuellen Tests und einem hohen Automatisierungsgrad erreichen. Generell lassen sich Softwaretests in verschiedene Teststufen Unit-, Integrations- und Systemtests (End-to-End-Testing/E2E-Tests) unterteilen.Die bekannte Testpyramide von Mike Cohen (Bild 1) basiert auf dieser Einteilung und bewertet diese mit den Faktoren Anzahl und Aufwand. Basis der Testpyramide bilden die Unit-Tests – von denen es eine recht große Anzahl gibt.
Oberhalb der Testpyramidebefinden sich die manuellen Tests, diese sollte man aufgrund ihres hohen Arbeitsaufwands auf ein Minimum reduzieren(Bild 1)
Simon
Unit-Tests bilden das solide Fundament der Testpyramide – sie gelten als schnell durchführbar und einfach zu warten. Die mittlere Ebene bilden die Integrationstests mit längeren Ausführzeiten und mehr Pflegeaufwand. Um ihre Anzahl zu reduzieren, sollten sich Integrationstests auf die Prüfung kritischer Schnittstellen konzentrieren. In der Spitze der Testpyramide befinden sich die Systemtests. Nur sie bewerten ganzheitlich, ob die Anwendung in ihrer Gesamtheit funktioniert. Im Unterschied zu allen anderen Testarten/typen bedeutet die Durchführung der Systemtests einen hohen Zeitaufwand. Eventuelle Änderungen der Software bewirken somit immer einen hohen Wartungsaufwand in den Systemtests.
Effektives und wirtschaftliches Testmanagement
Das Qualitätsmanagement sollte sich der Tatsache bewusst sein, dass aus der zunehmenden Automatisierung von Tests mit einem massiven Anstieg an Systemtests zu rechnen ist. Der Einsatz von Werkzeugen für die Testautomatisierung bewirkt eine höhere Produktivität bei den Testern. Tester erstellen in wesentlich kürzerer Zeit immer schneller, komplexere und anspruchsvollere Systemtests. Das von den Testern erworbene Fachwissen führt zu einer steigenden Anzahl an Testfällen. Intensivere Diskussionen der Fachabteilung mit dem Testmanagement trägt tendenziell zu einer Erhöhung der manuellen Tests bei.Insgesamt betrachtet, droht dann die Gefahr, dass wie bei den Unit-Tests eine große Anzahl an Systemtests und manueller Tests auch in den Fachbereichen existiert. Die Verteilung der Testarten/typen entspricht anschließend nicht mehr einer Pyramide, sondern im Extremfall einem spitzen Eisbecher (Bild 2). Qualitäts- und Testmanager müssen diese Tendenz rechtzeitig erkennen, steuernd eingreifen und eventuell Gegenmaßnahmen einleiten. Der Aufwand zur Ausführung und Wartung von Systemtests sollte sich nicht negativ auf die Entwicklungsproduktivität auswirken. Zudem darf die steigende Anzahl der in den Fachbereichen durchzuführenden manuellen Tests nicht die bisher zuverlässige Abwicklung ihrer gängigen Aufgaben behindern.
Mit zunehmender Automatisierungder Testfälle kehrt sich die Testpyramide um – es droht die Gefahr eines zu großen für das Projekt ungerechtfertigten Testaufwands(Bild 2)
Simon
Zielführend kann es sein, die Fachabteilungen mit in das Testmanagement so zu integrieren, dass einige der manuellen Tests ebenfalls automatisiert werden. Anschließend sollte die Fachabteilungen in die Lage versetzt werden, die automatisierten Testfälle eigenständig zur Ausführung zu bringen, als auch die Testergebnisse auswerten zu können.Die zunehmende Anzahl automatisierter Systemtests und der steigende Anteil der Automatisierung bisher rein manueller Tests wirkt sich positiv auf die Testabdeckung des gesamten Softwaresystems aus. Damit erhöht die Automatisierung der Tests nicht den Aufwand oder die Kosten, bewirkt aber auf jeden Fall eine höhere Qualität für die gesamte Anwendung.
Testen erstreckt sich über den gesamten Software-Lebenszyklus
In der testgetriebenen Entwicklung von Software finden alle Arbeiten für das Testen kontinuierlich über den gesamten Lebenszyklus statt. Insbesondere dann, wenn die Qualitätssicherung eine wichtige Rolle bei den Auftraggebern einnimmt. Dies bedeutet, dass es in der Software-Entwicklung zwei Prozesse (oder anders ausgedrückt Zyklen) gibt: den Software-Entwicklungs- und den Software-Test-Lebenszyklus. Während der Entwicklungsprozess die Phasen Planung, Anforderungsanalyse, Design, Implementierung, Test, Bereitstellung und Wartung iterativ und mit Zyklen durchläuft - umfasst der Testprozess, den das Testteam verfolgt, ähnliche Phasen wie die Entwicklung.Der Testprozess zielt jedoch darauf ab, mit den Arbeiten im Software-Test-Lebenszyklus die Qualität der Software sicherzustellen. Die Phasen des Software-Test-Lebenszyklus lässt sich in Anforderungsanalyse, Testplanung, Testentwurf, Einrichtung der Testumgebung, Durchführung der Softwaretests und Dokumentation des Testabschlusses einteilen. Die Anforderungsanalyse des Entwicklungsprozesses ermittelt die gesamten Anforderungen, die es umzusetzen gilt. Dieser Anforderungskatalog fließt in die Anforderungsanalyse bei der Konzeption der Testfälle ein. In der Phase der Testplanung legt das Testteam Strategien und Ansätze für das Testen der Testfälle fest.Apple unterstützt JavaScript direkt in JavaScriptCore
Mit der Entwicklung von WebKit entstand eine eigene HTML- und JavaScript-Engine: WebCore, JavaScriptCore. Seit vielen Jahren steht in Apples Betriebssystem der JavaScript-Interpreter JavaScriptCore zur Verfügung. Neben der HTML-Rendering-Engine WebCore ist JavaScriptCore in macOS integriert und kann zur Programmierung verwendet werden.
Der Testentwurf konkretisiert die Testfälle anhand einer Reihe durchzuführenden Aktionen, um ein bestimmtes Feature oder Funktion der Software zu überprüfen. Nach dem Einrichten der Testumgebung stehen Hardware und Software in einer Umgebung bereit, in der das Softwaresystem validiert werden kann.Die Phase Durchführung der Softwaretests prüft die Anwendung auf mögliche Fehler und Mängel; dabei versuchen die Tester diese möglichst vollständig zu ermitteln. Der Testabschluss zielt darauf ab, die Ergebnisse der ausgeführten Tests zu ermitteln und zu dokumentieren. Die Dokumentation der Testergebnisse dient als Ausgangspunkt, um mögliche Qualitätsmängel im Softwaresystem zu finden und zu beseitigen.
Verschiedene Teststufen
Teststufen, auch Testebenen genannt, orientieren sich immer an einem konkreten Vorgehensmodell, das in der Regel aus den Phasen Planung, Anforderungsanalyse, Systementwurf und Programmierung besteht. Auf die Ergebnisse dieser Phasen des Vorgehensmodells richten sich die jeweiligen Test- oder Prüfaktivitäten aus (Bild 3).
Die Ergebnisse der Phasendes konkreten Vorgehensmodells bilden die Grundlage für die Prüfung in den verschiedenen Testarten/stufen/ebenen(Bild 3)
Simon
Diese Kopplung bedeutet eine Prüfung der Programmierung erfolgt im Entwicklertest, die des Systementwurfs (Anwendungsarchitektur) übernimmt der Integrationstest, die Anforderungsanalyse überprüft der Systemtest und die Planungsergebnisse kontrolliert der Abnahmetest. Die Ergebnisse aller durchgeführten Tests fließen in die Beurteilung der realen Qualität des Softwaresystems ein.Unabhängig vom individuell ausgeprägten Vorgehensmodell findet man in der Regel mindestens die vier folgenden Teststufen; diese enthält auch der Lehrplan des ISTQB (International Software Testing Qualifications Board) – einer gemeinnützigen Zertifizierungsstelle für Softwaretester:Der Testprozess orientiert sich an einem Phasenmodell, dessen Phasen die verschiedenen Autoren unterschiedlich bezeichnen. Betrachtet man jedoch deren Inhalt so stellt man im Wesentlichen fest, dass dieser nahezu identisch ist. Der ISTQB unterteilt den Testprozess in die folgenden Hauptaktivitäten oder Phasen: Planung & Steuerung, Analyse & Entwurf, Realisierung & Durchführung, Bewertung der Endekriterien & Bericht sowie Abschluss der Testaktivitäten. Für die einzelnen Testobjekte erfolgt die Durchführung der mit den jeweiligen Phasen verbundenen Aktivitäten in der Regel mehrfach. Eine derartige Testwiederholung bezeichnet der ISTQB als Testzyklus. Die eigentliche Ausführung der Testaktivitäten übernehmen aufgrund der vielfältigen Aufgaben verschiedene im Software-Lebenszyklus beteiligte Personen. Zu den wohl wichtigsten Rollen mit den nachfolgenden Verantwortlichkeiten gehören:In agilen Vorgehensmodellen stehen eine schlanke Organisation des Teams und eine flexible, inkrementelle und iterative Arbeitsweise im Vordergrund. Zusammen mit der testgetriebenen Entwicklung (TDD) entstand als agile Form der Softwareentwicklung die BDD (Behavior-Driven-Development/Verhaltensgetriebene Softwareentwicklung); manchmal auch SDD (Specification Driven Development/Anforderungsgetriebene Software-Entwicklung) genannt. Beim Test-Driven-Development (TDD) werden die Testfälle vor der eigentlichen Programmierung der Software definiert, um diese später (möglichst) automatisch zu testen.
Verhalten der Software aus Sicht des Endbenutzers
Im Unterschied dazu fokussiert BDD/SDD auf das gewünschte Verhalten der Software aus Sicht des Endbenutzers. Dabei beschreiben die Beteiligten dieses Verhalten in einer Sprache, welche die Umsetzung in Software erleichtert. Somit rückt die fachliche Beschreibung der Software in den Mittelpunkt – es entstehen Fallbeispiele (Szenarien genannt), welche nicht nur als Grundlage für die Anforderungsspezifikation, sondern auch für die Automatisierung der Tests dienen. Insofern eignet sich BDD vor allem bei komplexen Entwicklungsprojekten, da eine schrittweise Ausarbeitung von Fallbeispielen mit fortschreitendem Detaillierungsgrad entsteht. Entscheidend hierbei ist die Einbindung von geeigneten Vertretern aller betroffenen Fachbereiche.
Zu Spezifikationsworkshopstreffen sich bedarfsorientiert Vertreter aus drei Bereichen, da die Einbindung verschiedener Sichtweisen die Akzeptanz der Anwendung und damit deren Qualität erhöht(Bild 4)
Simon
Nur wenn sich unterschiedliche Sichtweisen in den Szenarien des BDD widerspiegeln, ist eine spätere Übereinstimmung des Software-Systems mit den fachlichen Anforderungen garantiert. Um dies sicherzustellen, kommt das Three-Amigos-Prinzip zum Einsatz. Dieses Prinzip zielt auf die Besetzung des BDD-Teams ab (Bild 4); es sollen Vertreter aus dem Fachbereich, der Entwicklung und des Tests eingebunden werden. Somit fließen drei unterschiedliche Sichtweisen in die BDD-Szenarien ein:Im Rahmen des BDD/SDD hat das Three-Amigos-Team eine Reihe von Testfällen konkretisiert. Dabei kommt als Beschreibungssprache häufig die Gherkin-Notation zum Einsatz. Als semi-formale Sprache bietet Gherkin einen hohen Freiheitsgrad in der Ausgestaltung ihrer Beschreibungen.Insofern können die Inhalte in beliebiger natürlicher Sprache formuliert werden. Diese müssen lediglich seitens ihrer Struktur sich an das von Gherkin vorgegebene Schema Given-When-Then orientieren. Dabei legt Given die Vorbedingung des Fallbeispiels fest, When beschreibt die ausgeführte Aktion und Then die seitens der Software erwartete Reaktion. Zusätzlich sind noch andere Schlüsselwörter wie And, Not und zusätzliche möglich.
Beschreibungssprache standardisiert Testfälle
Als Werkzeuge für BDD mit Gherkin bietet sich Cucumber oder alternativ Mochas BDD-Syntax an. Dabei dient Gherkin primär als Kommunikationssprache im Three-Amigos-Team. Ihr Einsatz führt zu verständlichen Spezifikationen und zu einer grundlegenden Dokumentation des Systemverhaltens. Gleichzeitig dienen die Gherkin-Ergebnisse als Ausgangsbasis für eine anschließende Automatisierung der Testfälle. Damit wird die besondere Bedeutung von BDD zur Vermeidung falsch verstandener Anforderungen und Verhalten der Software klar. Bei BDD mit Gherkin handelt es sich also um eine Entwicklungsstrategie, welche vor allem die Kommunikation aller Beteiligter verbessert.Als Ergänzung zu Gherkin kann man Chai – eine BDD/TDD-Assertion-Library einsetzen. Mit der BDD-Syntax dieser JavaScript-Bibliothek formuliert man sogenannte Assertions (Zusicherungen); dabei handelt es sich um Bedingungen, welche die zu testenden Software erfüllen soll.Die beiden Hauptkonstrukte von Chai lassen sich mittels weiterer Sprachelemente verketten, die als Getter fungieren. Grundsätzlich findet die eigentliche Automatisierung der Testfälle nicht im BDD vielmehr in einem nachgelagerten daran anschließendem Entwicklungsschritt statt. Verbindet man jedoch die inhaltlichen Beschreibungen der Gherkin-Dateien mit den Testfällen, so lassen sich diese schnell finden und direkt ausführen.Mocha für den Testaufbau
Das JavaScript-Testframework Mocha basiert auf Node.js und besitzt eine Reihe von Interfaces, um den Aufbau von Tests zu definieren. Standardmäßig kommt BDD zum Einsatz – jeder Testfall entspricht einer JavaScript-Datei. Der Namen dieser JavaScript-Datei soll sich an der Aufgabe des Testfalls orientieren.Ein Testfall im Vokabular von Mocha nennt sich Testsuite, diese setzt sich aus verschiedenen Teststeps zusammen. Für die Ausführung einer Testsuite müssen bestimmte Voraussetzungen erfüllt sein – in Mocha Testhook genannt. Als Sprachmittel für die Definition der Testsuite kommt describe() zum Einsatz.Im ersten Parameter von describe() vergibt man den Namen der Testsuite und der zweite Parameter definiert eine Funktion. Diese Funktion von describe() dient als Spezifikation für die komplette Testsuite. Zu Beginn dieser Funktion richtet ein Testhook (mittels before, beforeEach(), after, afterEach) alle für die Ausführung der Testsuite notwendigen Voraussetzungen ein. Sind alle Voraussetzungen erfüllt, so erfolgt die Ausführung beziehungsweise Prüfung von Testfällen mittels des it()-Feature von Mocha. Dabei übergibt man im ersten Parameter den Namen des Testcase, der zweite definiert eine JavaScript-Funktion. Innerhalb dieser it()-Funktion erfolgt die Überprüfung des Testcase mittels verschiedener Teststeps.Kontinuierliche Erweiterung von Cypress Studio
Für die nächsten Versionen hat der Hersteller die Generierung weiterer Cypress-Befehle über das Recording-Feature von <br/>Cypress Studio angekündigt. Die Betaversion von Cypress Studio generiert derzeit anhand der durchgeführten Interaktionen mit der Web-App lediglich die Cypress-Befehle check, click, select, type und uncheck. Während dem Recording befinden sich in der Toolbar (Symbolleiste) von Cypress Studio neben der Bezeichnung STUDIO BETA zwei Schaltflächen: AVAILABLE COMMANDS und GIVE FEEDBACK. Bei Klick auf AVAILABLE COMMANDS öffnet in Cypress Studio ein Informationsfenster mit den aktuell unterstützten Cypress-Befehlen. Über GIVE FEEDBACK können Anwender von Cypress Studio direkten Kontakt zu den Entwicklern beim Hersteller aufnehmen.
Die Spezifikation der Überprüfungen innerhalb der Teststeps erfolgt mittels Assertions (Zusicherungen). Für die Formulierung einer Assertion greift Mocha auf das eigene (Built-in-Modul assert) oder auf eine leistungsfähiges JavaScript-Assertion-Library wie Chai, Expect.js oder Should.js zurück. Diese Assertion-Libraries basieren ebenfalls auf Node.js. Chai als Assertion-Library bietet verschieden Stile für die Formulierung von Assertions mittels assert, expect oder should.Chai bietet die Möglichkeit eigene Sprachkonstrukte für die Formulierung von Assertions einzurichten. Dazu steht ein Plugin-Interface zur Verfügung. Die Chai-Community hat bereits eine Vielzahl von Plugins programmiert, um spezielle Assertions formulieren zu können. Über derartige Plugins lassen sich auch aktuelle Technologien wie AWS DynamoDB, CSS, Firebase, jQuery, JSON-Schemata, Protractor, React oder Webdriver einbinden.
Inkrementelles Testen
Das in der Entwicklung eingesetzte Vorgehensmodell muss so gestaltet sein, des es die erforderliche kontinuierliche Verbesserung unterstützt. Deshalb muss das Vorgehensmodell und die mit ihm verbundenen Prozesse eine hohe Agilität besitzen und auf eine iterative Arbeitsweise ausgerichtet sein. Dieser Sachverhalt gilt insbesondere auch für die Tätigkeit des Testens und den Testprozess insgesamt. Während des Entwicklungsprozesses entstehen aufgrund der inkrementellen Arbeitsweise zu unterschiedlichen Zeiten verschiedene Arbeitsergebnisse, die es zu testen gilt. Dabei muss grundsätzlich eine Funktionsweise des Gesamtsystems mit einer hohen Qualität gewährleistet werden.Deshalb müssen die einzelnen Arbeitsergebnisse umgehend zu einem Gesamtsystem integriert und getestet werden. Dies verdeutlicht die besondere Rolle des Integrationstest: Er stellt sicher, dass sich die verschiedenen Einzelergebnisse, welche zusammen arrangiert werden, auch wie ein funktionsfähigen Gesamtsystem agieren. Da nicht immer alle für das Gesamtsystem notwendigen Arbeitsergebnisse in ihrer vollständigen Funktionsweise vorliegen, müssen für den Test einzelner Moduln (Arbeitsergebnisse) Schnittstellen noch nicht realisierter Moduln simuliert werden. Die Durchführung derartiger Simulationen erfolgt mit speziell erstellten Testobjekten:Im Falle von JavaScript greift man zur Realisierung derartiger Testobjekte auf ein sogenanntes Mocking-Framework zurück. Ein bekanntes Framework für Stubbing und Mocking ist Sinon.JS, das lediglich eine Installation von Node.js benötigt. Deshalb lässt es sich auch zusammen mit anderen Unit- oder BDD-Testframework einsetzen. Sinon.JS arbeitet auch mit TDD-Frameworks (Buster.js, Cypress) zusammen, da es in diese integriert ist. So kann man Sinon.JS für das Testen einer Web-App zusammen mit Mocha, Chai und Istanbul verwenden (Bild 5).
Für Integrations- oder Unit-Testseignen sich Mocha (BDD/Testsuites), Chai (Assertions), Sinon.JS (Mocking/Spy) und Instanbul (Code-Überdeckung)(Bild 5)
Simon
Über Mocha definiert man mittels BDD-Methode die Testsuites mit ihren verschiedenen Testcases und Teststeps. Erforderliche Assertions formuliert man mit Chai. Eventuell notwendige Fakes, Stubs, Mocks und Spies realisiert man über Sinon.JS.
Cypress mit mächtigen Features
Das Testframework Cypress für Web-Apps basiert auf Mocha und Chai und benutzt Node.js bei der Ausführung von Testfällen innerhalb eines Webbrowsers. Für die Programmierung von Tests kommt JavaScript zum Einsatz, dabei bietet Cypress vollständige Unabhängigkeit von dem in der Entwicklung eingesetzten JavaScript-Framework/Library. Cypress unterstützt alle Browser, die zur Chrome-Familie (Chromiums) gehören, wie Edge, Firefox, Opera aber auch das Node.js-System Electron. Eine Unterstützung des Safari-Browser befindet sich derzeit noch in Entwicklung.Im Unterschied zum länger verfügbaren Selenium-Framework erfolgt die Installation und das Einrichten von Cypress völlig npm-konform ohne jedweden Zusatzaufwand. Alle auf dem Testsystem installierten Browser kann man direkt nutzen; während Selenium lediglich Headless Browser (Webbrowser ohne GUI) unterstützt. Bei der Ausführung von Tests besitzt Cypress eine hohe Performance, verbunden mit einer automatischen Waiting-Utility – so dass man keine eigenen Waits definieren muss. Das Testing-Framework wartet eigenständig auf die Verfügbarkeit beispielsweise von Animationen, DOM-Loading, Elementen und ähnliches.Cypress führt spezifizierte Tests in der vorgegebenen Reihenfolge durch, damit entfallen Ausfallzeiten oder das manuelle Anstoßen nachfolgender Testfälle. Im Unterschied zu Selenium benötigen Entwickler kein zusätzliches nicht-toolspezifisches Wissen, JavaScript- und Cypress-Kenntnisse reichen aus. Damit werden auch Entwickler in die Lage versetzt, eigene Tests zu programmieren, was den gesamten Entwicklungsprozess beschleunigt. Als freizugängliche Software mit Open-Source-Lizenz steht Cypress für die komplette JavaScript-Gemeinde zur Verfügung. Zusätzlich benötigte Features oder Produktsupport stellt der Hersteller über verschiedene Abonnements bereit.Derzeit gilt Selenium immer noch als De-facto-Standard für das automatisierte Testen von Web-Apps. Aufgrund der besonderen Features von Cypress nimmt die Anzahl der Nutzer des Testframeworks aktuell rapide zu. Vor allem wegen den vielen zusätzlichen Features, die man inzwischen auf dem Software-Markt für Cypress findet. Derzeit sollte man prüfen, ob man nicht mit Cypress einfacher, vor allem aber produktiver als mit Selenium arbeiten kann. In diesem Fall macht es Sinn, Selenium nur noch für Aufgabenstellungen einzusetzen, die Cypress noch nicht abdeckt.Installation und Einrichten von Cypress
Für die Einrichtung von Cypress benötigt man ein installiertes Node.js-System in einer aktuellen Version mit dem Node Package Manager (npm). Die Installation von Cypress erfolgt am einfachsten als npm-Package im Projektordner der Web-App. Der Terminalbefehl npm install cypress --save-dev trägt das Cypress-Package als Entwicklungsabhängigkeit in der package.json ein.Alle zu Cypress gehörenden Bestandteile befinden sich anschließend im Verzeichnis node_modules/.bin/cypress. Führt man im Terminalfenster den Befehl node_modules/.bin/cypress open aus, so startet der Test Runner von Cypress (Bild 6); anschließend legt er im Projektordner ein neues Unterverzeichnis cypress an. In der rechten oberen Ecke des Test Runner befindet sich eine Drop-Down-Liste; sie zeigt alle auf der Hardware verfügbaren Webbrowser an. Den darüber ausgewählten Browser verwendet Cypress bei der Ausführung der Testfälle.
Testfällekönnen auf dieser Hardware über den Test Runner von Cypress mit einem der drei Browsern Chrome, Firefox, Edge oder Electron ausgeführt werden(Bild 6)
Simon
Als Standardbrowser dient Electron; der in jeder Cypress-Version integriert ist – damit entfällt eine separate Installation von Electron. Electron sollte auch für das Debugging von Testfällen mit Cypress eingesetzt werden. Die beim Browsernamen angezeigte Zahl weist auf die in ihm verwendete Chromium-Version hin. Probleme beim Starten des Cypress Test Runner bereinigt cypress cache clear für alle auf der Maschine vorhandene Versionen, die sich aktuell im jeweiligen Cache befinden. Anschließend überführt der Befehl [node_modules/.bin/]cypress install das Testtool wieder in einen konsistenten Zustand. Über den im Script-Bereich der package.json definierten Eintrag, legt man fest, wie man Cypress über npm ausführt.Das Script cypress open in der Datei cyop öffnet über den Befehl npm run cyop den Test Runner und startet alle Testfälle. Während das Script cyrun: cypress run über den Befehl npm run cyrun alle Testfälle ohne geöffneten Test Runner im headless-Mode ausführt. Beim erstmaligen Aufruf des Test Runners erzeugt Cypress die Konfigurationsdatei cypress.json. Definitionen dieser Datei legen das standardmäßige Verhalten von Cypress fest.So gibt der Eintrag „baseUrl“: „http://localhost:5000“ die vom serve-Package beim Testen einer Anwendung geöffnete URL vor. Standardmäßig verwendet Cypress den Port 5000. Viele der in cypress.json möglichen Einträge lassen sich auch direkt über JavaScript beim Schreiben der Tests beeinflussen. So setzt zum Beispiel der Parameter { timeout: 10000 } des get-Kommandos den DOM-Timeout auf 10 Sekunden.
IDE-Integration für Entwicklungsprojekte
Beim erstmaligen Aufruf des Test Runner versucht Cypress die auf dem Betriebssystem verfügbaren Programmierumgebungen (IDEs) zu finden. Cypress lokalisiert dabei Atom, Emacs, Sublime Text, Visual Studio Code oder Vim. Über das Settings-Menü im Test Runner legt man im Bereich File Opener Preference die gewünschte IDE fest. Im Bedarfsfall definiert man über das Eingabefeld Other eine beliebige andere IDE. Diese Vorgabe besteht aus dem vollständigen Pfad zusammen mit dem Programmnamen der IDE. Nach erfolgter Ausführung eines Testfalls öffnet ein Klick im linken Fensterausschnitt des Test Runners auf den dort angegebenen Dateinamen, die betroffene Zeile im Quellcode der zugeordneten IDE.Der Hersteller liefert Cypress zusammen mit den Type-Declarations für TypeScript aus. Alle Editoren, die derartige Type-Declarations verarbeiten, unterstützten über eine Trible-Slash-Directive die Code-Vervollständigung. Für Cypress gibt man dazu am Anfang der Quellcode-Datei die Kommentarzeile /// <reference types=“Cypress“ /> an. Eine derartige Trible-Slash-Anweisung aktiviert für die betroffene Datei das IntelliSense-Feature. Befindet sich in der tsconfig.json-Datei von TypeScript bei den compilerOptions der Eintrag “types“: [“cypress“], so erübrigt sich die Trible-Slash-Anweisung.Programmierung mit Cypress
Für die Programmierung mit Cypress steht Code-Vervollständigung (IntelliSense) zur Verfügung. Für einige IDEs zum Beispiel Visual Studio Code (VS Code) stehen auch Erweiterungen/Plugins speziell für Cypress zur Verfügung. So bietet der Cypress Helper (vscode-cy-helper) eine Fülle weiterer Features für ein automatisiertes Arbeiten mit Cypress an.
Jedes Entwicklungsprojektenthält den Ordner cypress mit weiteren Unterverzeichnissen für Testfälle, Konfigurationen, Erweiterungen oder Modifikationen von Cypress(Bild 7)
Simon
Beim erstmaligen Aufruf des Test Runner richtet Cypress im Entwicklungsprojekt einen Ordner cypress ein, der unter anderem vier Unterverzeichnisse (Bild 7) enthält:Zusätzlich kann der Test Runner weitere Datei-Verzeichnisse während der Ausführung eines Testfalls erzeugen. In der Regel legt der Test Runner in derartig erzeugte Ordner alle für die Ausführung eines Testfalls benötigte Ressourcen beispielsweise heruntergeladene Dateien oder Screenshots ab.
Fortschrittliche Architektur
Die Entwickler von Cypress legten besonderen Wert auf hohe Stabilität, große Zuverlässigkeit, schnelle Ausführungsgeschwindigkeit und produktive Programmierung der Tests. Die Realisierung von Cypress erfolgte mit JavaScript, Node.js und Electron. Die Architektur von Cypress aus dem Blickwinkel Ausführung eines Tests betrachtet, besteht aus zwei Prozessen: einem Node.js-Prozess auf der Serverseite und einem laufenden Webbrowser (Bild 8). Bei der Ausführung eines Testfalls befindet sich Cypress im selben Prozess wie die zu testende App. Dazu passt Cypress den Webbrowser so an, dass Cypress und der auszuführende Test in einem eigenen iFrame und die App in einem anderen iFrame abläuft.
Die Architektur von Cypress-Testsunterstützt derzeit nicht den Einsatz mehrerer Tabs im Browser, nicht den parallelen Betrieb verschiedener Browser für einen Test und auch nicht verschiedene Domain-Namen innerhalb eines Testfalls(Bild 8)
Simon
Somit führt Cypress den Testfall/code in einem eigenständigen iFrame und die App in einem anderen aus – während beide iFrames aber im selben Browser-Tab zur Ausführung kommen und daher dieselbe JavaScript-Loop verwenden. Der Testfall/code kommuniziert mit dem Node.js-Prozess über Websockets. Der Node.js-Prozess fungiert als ein Platzhalter/Proxy für jeden HTTP-Request des Browsers, so macht der Node.js-Prozess Cypress Ressourcen und Dienste des Betriebssystems zugänglich. Die Kontrolle des Netzwerkverkehrs erfolgt über den Proxy. Dieser fängt HTTP-Requests ab und ermöglicht den Cypress-Tests, auf die Erfüllung bestimmter Abfragen zu warten.Im Bedarfsfall können HTTP-Responses vollständig mit Fixtures überschrieben werden, anstatt die Requests an das echte Ziel zu senden oder auf ihre echte Response zu warten. Diese Vorgehensweise ermöglicht es, Responses zu fälschen, ohne die Anwendung für einen anderen API-Host konfigurieren zu müssen. Dies basiert alles auf dem Proxy, wenn man Cypress mit den richtigen Befehlen dazu anweist. Außer HTTP-Requests können auch die lokale Zeit und sogar JavaScript-Objekte während der Laufzeit überschrieben (Stubs) oder zu Prüfzwecken beobachtet (Spions) werden.Derartige Anpassungen beziehungsweise Protokollierungen helfen dabei, zeit- oder datumsabhängige Teile einer App zu testen. Die Manipulation von JavaScript-Objekten der App zielt darauf ab, eventuell notwendige Voraussetzungen seitens der App bereitzustellen. Damit lässt sich zum Beispiel die Anmeldung eines Benutzers simulieren, welche die Voraussetzung darstellt, um Funktionen der App überhaupt ausführen zu können. Dies verdeutlicht den Sachverhalt, dass man die Programmierung von Tests mit Cypress vereinfachen und beschleunigen kann. Der Entwickler eines Tests kann sich so auf das Schreiben der Testfälle für die App konzentrieren, so dass die Programmierung der Testfälle wesentlich produktiver erfolgt.
Erweiterbarkeit von Cypress
Das Verhalten der Apps bei der Anzeige und beim Layout gestaltet sich häufig sehr dynamisch. Dazu trägt auch die Verarbeitung der Dienste im Backend durch Simulierung manueller Benutzer-Interaktionen bei. Viele Testsysteme zur Automatisierung erfordern für dieses Verhalten die Programmierung von Waiting- und Wiederhol-Mechanismen innerhalb der Testfälle. Was wesentlich die Komplexität seitens der Bereitstellung des Testcodes erhöht. Der damit verbundene Zusatzcode verursacht sowohl in der Entwicklung der Testfälle als auch bei deren Ausführung zusätzlichen Arbeitsaufwand und Kosten. Dennoch ist nicht immer gewährleistet, dass die App sich bei der Durchführung der Testfälle deterministisch verhält.Cypress beugt selbständig, in der Regel ohne zusätzlichen Programmieraufwand, diesem Verhalten aufgrund der realisierten Architektur vor. Wie oben beschrieben, kontrolliert der Proxy den Netzwerkverkehr – unterbrochene HTTP-Requests warten auf die weitere Abarbeitung der Cypress-Tests. Damit besitzt Cypress die Fähigkeit auf die Ausführung abgesetzter Kommandos zu warten, bis diese beendet sind. Solange die Seite in der App nicht vollständig alle Elemente anzeigt, unterbricht Cypress die Testdurchführung. Dieser Mechanismus, Flake Resistance genannt, findet vollständig im Browser statt – es kommt nicht zu Verzögerungen über das Netz wie bei anderen Testingtools. Dieser Sachverhalt erleichtert das Schreiben von leicht lesbarem und verständlicherem Testcode.Alternative Testwerkzeuge für Ionic/Angular/React
Für Entwickler, die das volle Funktionsspektrum von Ionic nutzen wollen, empfiehlt sich der Einsatz von Cypress als Testframework. Sollte man lediglich Ionic mit Angular, React oder Vue einsetzen, haben sich nachfolgende Alternativen bewährt:
Wesentlicher Bestandteil bei der Durchführung automatischer Tests stellt die Protokollierung, das heißt die Aufzeichnung wichtiger Testergebnisse dar. Diese umfassen Änderungen im DOM sowie das Verhalten der App während der Ausführung des Tests durch Screenshots und Videos. Eine Protokollierung hilft bei der Lokalisierung möglicher Fehler, die während der automatischen Tests aufgetreten sind.Obwohl Cypress als Werkzeug funktionale Tests durchführt, können so auch visuelle Tests von Cypress unterstützt werden. Letztendlich bietet Cypress eine offene Architektur, die mittels Programmierung eigener Custom Commands, Plugins und Events, das Verhalten von Cypress verändern oder erweitern. So macht der Hersteller als auch die Community inzwischen eine Vielzahl von Plugins verfügbar.
Grundlegende Konstrukte
Wie andere Testframeworks für die Automatisierung von Testfällen basiert auch in Cypress deren Struktur auf den drei Grundbausteinen: Testsuite-Name, Testcase-Name und Teststeps. Während der Name der Testsuite einen kompletten Testfall beschreibt, entspricht der Name eines Testcase dem Namen/der Spezifikation einer innerhalb der Testsuite realisierten Funktion. Die Realisierung oder Umsetzung eines Testcase erfolgt mittels verschiedener Teststeps, deren Programmierung im jeweiligen Code-Block mittels spezieller Cypress-Konstrukte erfolgt.Für die Formulierung von Testsuite und Testcase greift Cypress auf das integrierte Mocha-Testframework zurück. Cypress verwendet dabei die vom Mocha-BDD-Interface vorgegebenen Namen (describe(), context(), it(), specifiy() und weitere):
// Name der Testsuite entspricht dem Dateiname
describe('Name der Testsuite', function () {
// Testcase
it('Name des Testcase', function (){
// Teststep fuer den Aufruf der URL
cy.visit("https://www.google.com/");
});
});
Wenn man Kenntnisse zu den grundlegenden Sprachkonstrukten besitzt, gestaltet sich die Programmierung der Testfälle in Cypress als recht einfach. Zur Einarbeitung in diese Sprachelemente enthält jeder Projektordner mit einer Cypress-Installation im Verzeichnis integration zwei Unterordner: 1-getting-started und 2-advanced-examples. Im ersten Unterverzeichnis befinden sich eine Reihe von einfachen Testfällen, welche das Testen mit Cypress anhand der bekannten Todo-Liste-App demonstriert.Die in der dortigen JavaScript-Datei todo.spec.js programmierten Testfälle führt man direkt durch Anklicken über den Cypress-Test Runner aus.Das andere Unterverzeichnis enthält die Realisierung einiger ausgewählte Problemstellungen mit Cypress-Sprachkonstrukten. Aus dem jeweils vorgegebenen Programmnamen leitet sich direkt die in der Datei realisierte Aufgabenstellung ab. So enthält die Datei cookies.spec.js Beispiele für das Testen von Cookies oder navigation.spec.js Beispiele für das Testen der Navigation innerhalb der App. Die Befehle von Cypress umfassen eine Reihe grundlegender Kommandos.Zu den wichtigsten Kommandos, die man nur direkt Lernen kann, gehören Assertions (Zusicherungen). Die zugeordneten Befehle führen innerhalb eines Testcase Prüfungen für den Teststep durch.Die Befehle umfassen: and, expect und should. Bei and handelt es sich um eine Alias-Bezeichnung für should – dieser Befehl verknüpft Prüfungen zu einer Assertion; legt also eine Assertion an. Die Prüfung einer Assertion direkt beim Objekt erfolgt mittels expect (assert).
Voraussetzungen für Test einrichten
Cypress kennt alle über das BDD-Interface von Mocha implementierten Sprachkonstrukte. Dazu gehören: before(), beforeEach() und after(), afterEach(). Das before()-Konstrukt schafft wie bereits erläutert, vor der eigentlichen Ausführung eines Testfalls (Testcase) alle notwendigen Voraussetzungen. Grundsätzlich sollte man darauf achten, dass alle Testfälle voneinander isoliert sind, das heißt eine sequentielle Ausführung der Tests beeinflusst nicht das einzelne Testergebnis. Deshalb führt Cypress, sobald mittels it() ein Testcase vollständig abgearbeitet ist, eine Bereinigung des Browser-State durch.Dies bedeutet für den nächsten auszuführenden Testcase muss man gegebenenfalls, neue Voraussetzungen für dessen korrekte Ausführung schaffen. Sollen für alle Testcases innerhalb einer Testsuite dieselben Voraussetzungen gelten, so definiert man diese mittels der beforeEach()-Anweisung. Ein beforeEach() am Anfang einer Testsuite stellt sicher, dass für jeden nachfolgenden über it() definierte Testcase immer die mit beforeEach() spezifizierte Voraussetzung vor dessen Ausführung erfüllt ist. Analog arbeiten after() und afterEach(): Mittels after() kann nach Abarbeitung eines it()-Testcase eine Bereinigung stattfinden, so dass der ursprüngliche Zustand vor dessen Durchführung wieder vorhanden ist.Soll eine solche Bereinigung nach jedem it()-Testcase vorgenommen werden, so greift man als Tester auf afterEach() zurück. Eine Schachtelung dieser BDD-Sprachkonstrukte untersagt Cypress nicht, diese kann aber zu schwer verständlichen Testfällen führen. Aus diesem Grund sollte man auf eine derartige Verschachtelung am besten verzichten. Im Unterverzeichnis support des cypress-Ordners eines Entwicklungsprojekts befindet sich die index.js-Datei. Soll für alle Tests die gleiche Ausgangssituation vorliegen, gewissermaßen eine globale Vorbereitung für alle Testsuites vorgenommen werden, so setzt man beforeEach() in der index.js-Datei ein. Damit stellt man sicher, dass vor der Durchführung aller Testsuites immer dieselbe Ausgangssituation vorliegt.Erkunden und Erzeugen
Die Programmierung der Testschritte/Teststeps innerhalb einer Testsuite erfolgt mit dem seitens Cypress bereitgestellten API. Programmierer und Tester nutzen die Befehle des Cypress-APIs und setzen auf der Basis von JavaScript/TypeScript die einzelnen Teststeps um. Dazu benötigt man Kenntnisse über die Syntax und Semantik des Cypress-API, das heißt zur Funktionsweise der Befehle und der mit ihnen verbundenen Parameter. Zusätzlich besitzt Cypress eine Schnittstelle, um das API mit eigenen Befehlen, sogenannte Custom Commands, zu erweitern oder bestehende Befehle zu verändern. Die Definition neuer beziehungsweise das Überschreiben vorhandener API-Befehle erfolgt in der cypress/support/commands.js-Datei.Um den Einstieg in das Arbeiten mit dem Cypress-API zu erleichtern, bietet es sich als Programmierer von Teststeps an, eines der Tools Cypress Recorder von KabaLabs, Fd Cypress Recorder, Cypress Scenario Recorder oder Cypress Studio von Cypress zu nutzen. Während die drei erstgenannten Werkzeuge einer Erweiterung der auf Chrome-basierenden Browser entspricht, handelt es sich bei Cypress Studio um ein im Cypress Test Runner integriertes Tool. Im Unterschied zu den drei Chrome-Erweiterungen befindet sich Cypress Studio derzeit allerdings noch im Betastadium. Die Installation einer Chrome-Erweiterung erfolgt in einem Chrome-basierenden Browser über den Chrome Web Store.Nach erfolgreicher Suche des Cypress Recorder im Chrome Web Store (Bild 9) wählt man einen der angezeigten Erweiterungen aus und klickt zur Installation auf die Hinzufügen-Schaltfläche. Der Microsoft Edge-Browser setzt für die Anzeige der Hinzufügen-Schaltfläche voraus, dass man in Edge die Berechtigung Installationen über den Chrome Web Store zulassen eingerichtet hat. Anschließend befindet sich das zugehörige Icon der Chrome-Erweiterung in der Symbolleiste des Webbrowsers. Die Funktionen der Cypress Recorder-Erweiterung erreicht man durch Klick auf das zugehörige Icon. Jetzt ist der Zeitpunkt gekommen, um die zu testende Web-App zu starten.
Im Chrome Web Storebefinden sich mehrere Erweiterungen für die Aufzeichnung beziehungsweise Generierung von Cypress-Befehlen(Bild 9)
Simon
Klickt man anschließend auf das Icon der Chrome-Erweiterung beginnt das Feature Start Recording mit der Aufzeichnung von Cypress-Befehlen. Dazu arbeitet man über die Web-App den zu programmierenden Testcase/Teststep ab. Nach dessen Ausführung wählt man die Funktion Stop Recording aus. Ein Klick auf die anschließend erscheinende Schaltfläche Copy to Clipboard befördert die generierten Cypress-Befehle in die Zwischenablage. Darüber kopiert der Tester die erzeugten Cypress-Befehle in den Quellcode der zugehörigen Testsuite, die zur Ausführung des betroffenen Testfalls vorgesehen ist. Um die Aufzeichnung fortzusetzen, greift man auf die Resume/Restart-Funktion der Chrome-Erweiterung zurück.
Studio bietet mehr Funktionsumfang
Für die Generierung von Cypress-Befehlen eignet sich zwar eine der genannten Chrome-Erweiterungen; allerdings arbeiten diese immer als eigenständiges Werkzeug. Jede dieser Chrome-Erweiterung besitzt individuelle Spezifika, die man für eine effiziente Aufzeichnung der API-Befehle beachten muss. Dies betrifft zum einen die individuellen Einstellungen, aber auch die jeweiligen Besonderheiten bei der Erzeugung der relevanten Cypress-API-Befehle. Will man die Aufzeichnung der Cypress-Befehle integriert mit dem Test Runner von Cypress vornehmen, so empfiehlt es sich Cypress Studio einzusetzen.Der Hersteller liefert Cypress Studio derzeit nur im Betastatus aus; für ihren Einsatz benötigt man in die cypress.json-Konfigurationsdatei den Eintrag: „experimentalStudio“: true. Zusätzlich trägt man noch die Adresse des Webservers ein, der die zu testende Web-App ausführt. Dazu verwendet man in der cypress.json-Datei zum Bespiel die Angabe „baseUrl“: „http://localhost:8080/“. Um das Recording-Feature von Cypress Studio zu nutzen, muss der Test Runner die Web-App über einen der im Hintergrund laufenden Webbrowser starten. Dazu programmiert man in der JavaScript-Datei (starte-app.js) eine Testsuite, die folgenden Befehl enthält: cy.visit(‚/‘).Startet man jetzt Cypress mit dem Befehl cypress open run, so öffnet sich der Test Runner. Klickt man danach mit dem Mauszeiger auf die soeben erstellte JavaScript-Datei starte-app.js, so öffnet Cypress den in der rechts obenstehenden Auswahlliste angegebenen Webbrowser und startet die Web-App. Der sich öffnende Webbrowser führt die Testsuite über die Web-App aus und zeigt in seinem linken Fensterausschnitt das zugehörige Protokoll an. Das nach der Testausführung angezeigte Protokoll nennt sich in Cypress Command Log. Um Cypress Studio für eine Recording-Session zu starten, klickt man im Command Log auf das kleine Zauberstab-Icon Add Commands to Test.
Das Testframework Cypressenthält das im Betastatus befindliche Recording-Tool Cypress Studio, das für alle Interaktionen mit der zu testenden Web-App automatisch die passenden Cypress-Befehle erzeugt(Bild 10)
Simon
Das Icon mit dem kleinen Zauberstab findet man im Command Log beim Namen des jeweiligen Testcase, der über die it()-Funktion definiert wurde. Nach der Auswahl von Add Commands to Test startet Cypress Studio und zeigt sein Begrüßungsfenster (Bild 10) an. Ein Klick auf die Get Started-Schaltfläche beginnt das Recording: Jede anschließend vom Tester ausgeführte Aktion mit der Web-App erzeugt im Hintergrund die zugehörigen Cypress-Befehle. Alle aufgezeichneten Cypress-Befehle zeigt der Test Runner im linken Fensterausschnitt Command Log an. Der Command Log enthält ganz unten jetzt zwei Schaltflächen Cancel und Save Commands. Klickt der Tester auf Save Commands, so legt Cypress Studio alle generierten Cypress-Befehle als neuen Teststep in der zur aktuellen Testsuite gehörenden JavaScript-Datei ab.
Generierung von Assertions
Assertions (Zusicherungen) zielen primär auf die Ausführungsphase der Testfälle ab und prüfen deren fachliche Korrektheit und Integrität. Grundsätzlich gilt, dass eine Assertion innerhalb eines Testfalls die korrekte Verarbeitung der Daten seitens der Web-App überprüft. Häufig handelt es sich bei den Assertions um Bedingungen, welche die Web-App im Testfall einzuhalten hat. Liegen diese als Beschreibungen in Textform vor, so gilt es aus diesen fachlichen Beschreibungen, geeignete Prüffunktionen abzuleiten, die der Tester mit Cypress-Befehlen programmiert. Objekt der Prüfung stellen letztendlich immer Daten und deren Bearbeitung durch die Web-App dar.Die über einen Testfall an die Web-App übergebenen Daten stellen die Eingabe dar. Einige nach der Verarbeitung der Eingabedaten von der Web-App ausgewählte Ausgabedaten bilden zusammen mit den Eingabedaten den Prüfling. Eine Assertion (Zusicherung) führt aufgrund eines derartigen Prüflings den Test auf fachliche Korrektheit durch. Als endgültiges Resultat der Prüfung liefert der Testfall einen booleschen Wert zurück. Bei der Programmierung des Testfalls mittels Cypress stehen dem Tester die Assertions-Library Chai und zusätzlich auch deren Erweiterungen Sinon-Chai sowie Chai-jQuery zur Verfügung.Recording mit Cypress Studio
In der Regel dienen die Sprachmittel der beiden Chai-Erweiterungen als Verknüpfung für vorhandene Cypress-Statements. Somit ergibt sich für die Assertion eine Kette von mehreren hintereinander ausgeführten Befehlen. Dabei kommen die Chai-jQuery-Erweiterungen häufig zusammen mit DOM-Objekten/Kommandos zum Einsatz. Im Unterschied dazu greift die Sinon-Chai-Erweiterung grundsätzlich auf die stub/spy/mock-Features zurück. Während dem Recording mit Cypress Studio definiert man eine Assertion durch Auswahl des im Browser angezeigten Elements und Aufruf dessen Kontextmenüs (Bild 11). Über dieses Kontextmenü bietet Cypress Studio alle dazu gehörenden passenden Erweiterungen für die genauere Spezifikation der Assertion an.
Während des Recordingsunterstützt Cypress Studio den Tester bei der schrittweisen Spezifikation von Assertions(Bild 11)
Simon
Anfangs beginnt der Tester mit der Aufzeichnung eines Testfalls in einer Testsuite, die noch keinen vollständigen Testcase enthält. Über die Schaltfläche Add Commands to Test erzeugt Cypress Studio durch das Recording für diesen Testcase einen weiteren Teststep. Nach Klick auf Save Commands übernimmt Cypress Studio die generierten Befehle in den Teststep. Zusätzlich unterstützt Cypress Studio auch die Aufzeichnung eines neuen, das heißt weiteren Testcase in eine vorhandene Testsuite.Nach Auswahl der Titelleiste mit dem Namen der Testsuite erscheint rechts die Schaltfläche Add New Test. Ein Klick darauf startet das Recording für einen weiteren Testcase. Klickt man nach Aufzeichnung aller Interaktionen auf die Schaltfläche Save Commands, erscheint ein Dialogfenster Save New Test für die Definition der Bezeichnung des neuen Testcase. Diese Bezeichnung übernimmt Cypress Studio als ersten Parameter in den it()-Befehl von Mocha – aus allen aufgezeichneten Cypress-Befehlen des Recording generiert Cypress Studio die dazu gehörenden Teststeps.Cypress bietet unterschiedliche Möglichkeiten einen Testcase zu filtern, um nur bestimmte auszuführen oder andere zu überspringen. Dazu gehören die beiden Funktionen: .only und .skip. Verwendet man innerhalb einer Testsuite zusammen mit dem it-Sprachkonstrukt die Funktion .only also zum Beispiel: it.only(‘Testcase X‘, ()…), so kommen nur die so gekennzeichneten Testcases zur Ausführung. Ein Testcase innerhalb der Testsuite, die nicht mit der .only-Funktion verknüpft ist, wird nicht angestoßen. Umgekehrt verhält es sich mit Testcases, die mit der Funktion .skip() verbunden sind. Der Test Runner überspringt alle Testcases it.skip(‘Testcase X‘, ()…), führt diese also nicht aus.Fast man mehrere Testsuites in einer Datei zusammen, so bringt der Test Runner nur diejenigen zur Ausführung, die mit der .only-Funktion verknüpften sind: descript.only(‘Testsuite Y‘, ()…). Alternativ bietet es sich an, in der Cypress-Konfigurationsdatei cypress.json den Eintrag “testFiles“ aufzunehmen. Alle bei diesem Eintrag “testFiles“: “testsuiteX.js“, “testsuiteY.js“, … genannten Testsuites kommen beim Start des Test Runners zur Ausführung. Alle anderen nicht bei “testFiles“ gelisteten Testsuites, die sich im Verzeichnis integration von Cypress befinden, werden nicht ausgeführt.Bei der Spezifikation der Testsuites über den „testFiles“-Eintrag sind Wildcards zulässig. So wählt “*.kunde.js“ alle Testfälle im integration-Unterverzeichnis aus, die im Dateinamen die Zeichenkette kunde enthalten. Alternativ kann man über den Eintrag “ignoreTestFiles“ in der cypress.json-Datei festlegen, welche Testsuites beim Starten des Test Runner nicht angestoßen werden. Dazu übergibt man die Dateinamen, der nicht auszuführenden Testsuites an ein JavaScript-Feld/Array: “ignoreTestFiles“: [“*.kunde.js“, “testsuiteX.js“]. In diesem Beispiel bringt der Test Runner alle Testsuites mit einer der beiden Zeichenketten kunde oder testsuiteX im Dateinamen nicht zur Ausführung.
Fortschrittliche Fehlersuche nach Testausführung
In Anlehnung an die cypress.json-Konfigurationsdatei wirkt eine Übergabe eines Parameters über die --spec-Option. Ruft man den Test Runner mit dem Befehl cypress run --spec “cypress/integration/*.kunde.js“ auf, so führt Cypress alle Testfälle aus, die in ihrem Dateinamen die Zeichenkette kunde enthalten. Die Ausführung aller Testfälle, die sich in einem bestimmten Unterverzeichnis befinden, erreicht man mit dem Aufruf: cypress run --spec “cypress/integration/buchhaltung/*“.Dieser Aufruf des Test Runners stößt die Abarbeitung aller im Unterverzeichnis buchhaltung stehenden Testfälle an. Um Testfälle bei der Ausführung auszuschließen, greift man auf das !-Zeichen zurück. So hindert der Übergabeparameter “cypress/integration/*[!.kunde].js“ den Test Runner daran, Testfälle deren Dateiname die Zeichenkette kunde enthält, auszuführen.Der Test Runner zeichnet jede Ausführung einer Testsuite auf und zeigt diese im linken Fensterausschnitt Command Log des von Cypress automatisch gesteuerten Webbrowsers an. Die Titelleiste unterhalb der Informationsleiste mit dem Text Chrome wird von automatisierter Testsoftware gesteuert nennt sich Test Status Menu. Sie zeigt die Anzahl der Testcases, die vollständig ohne Fehler, die Anzahl der mit Fehler ausgeführten, die Anzahl der gerade in Ausführung befindlichen Testcases und die Zeitdauer für die vollständige Ausführung der kompletten Testsuite an. Zur näheren Erkundung der Testergebnisse klickt man im Command Log auf das kleine, vor dem Namen der Testsuite stehende Pfeil-Icon.Anschließend öffnet sich eine Drop-Down-Liste mit den Namen der enthaltenen Testcases. Ein Klick auf das grüne Häkchen öffnet eine Auswahlliste mit der Bezeichnung TEST BODY. Diese nummeriert jeden Teststep fortlaufend durch und zeigt unterhalb des zugehörigen Cypress-Befehls die ausgeführten HTTP-Befehle an. Klickt man mit dem Mauszeiger auf einen dieser HTTP-Befehle, erscheint rechts im Webbrowser der vom Test Runner aufgezeichnete Screenshot der Web-App – diesen nennt man auch App Preview. Mit den unterhalb des Screenshots vorhandenen Schaltflächen kann man die Auswirkungen dieser HTTP-Befehle innerhalb der Web-App näher erkunden und sich sequentiell anzeigen lassen.Programmierung von Teststeps
Bei der Programmierung von Teststeps muss man auf deren Unabhängigkeit von eventuell dynamischen Elementen der Web-App achten. Nur diese Unabhängigkeit stellt eine automatische Ausführung der Teststeps sicher. Cypress Studio versucht anhand einer intelligenten Strategie die passenden Elemente beim Recording aus der Web-App auszuwählen. Diese Strategie basiert auf der Bestimmung eines eindeutigen Selectors anhand einer Reihe favorisierter Selectoren. Sollte es dennoch zu einem unerwarteten Fehler bei der Testausführung kommen, so befindet sich in der Titelleiste der App Preview neben der URL-Adresse das Icon-Symbol Open Selector Playground (Bild 12).
Das Icon Open Selector Playgroundhilft bei der interaktiven Definition von Selectoren über die App Preview für den cy.get()-Befehl(Bild 12)
Simon
Ein Klick darauf öffnet den Selector Playground und eine Positionierung des Mauszeigers über die Elemente der Web-App zeigt die zugehörigen Selector-Befehle an. Ein Mausklick auf das gewünschte Element übernimmt die zugehörigen Selector-Befehle mit den Parametern in das cy.get()-Eingabefeld. Um zu überprüfen, welche Elemente der Selector eines Teststeps anspricht, gibt man diesen Selector mit den Parametern direkt beim cy.get()-Befehl ein. Anschließend markiert der Test Runner im App Preview das gefundene Element und hinterlegt es mit einer hellblauen Markierung. Erscheint im cy.get()-Eingabefeld der Selector-Befehl in roter Farbe, so existiert im App Preview kein passendes Element.
Protokollierung der Ausführung
Cypress umfasst neben dem Test Runner auch noch einen Dashboard-Service zur Aufzeichnung ausgeführter Tests. Cypress Dashboard gibt es in vier verschiedenen Ausstattungen: Free, Team, Business und Enterprise. Jede der drei zuletzt genannten kostenpflichtigen Ausgaben baut auf der vorhergehenden Version auf und besitzt darüber hinaus weitere Features. Während Tester die Free-Version kostenlos nutzen können, fällt für die anderen drei Versionen eine monatliche Lizenzgebühr an. Wobei sich die Gebühren der Enterprise-Version an der Anzahl der maximal im Protokoll gespeicherten Testergebnisse orientieren.Die Free-Version des Dashboards erlaubt drei Benutzer und maximal 500 protokollierte Testergebnisse. Eine unbegrenzt große Anzahl an Tester setzt den Erwerb einer Enterprise-Ausgabe voraus. Der Dashboard-Service läuft im Web als SaaS, so dass man keine eigene Infrastruktur oder gar weiteres Personal für dessen Betrieb bereitstellen muss. Nach dem Einrichten eines Benutzeraccounts und Bestätigung der E-Mail-Adresse steht der Cloud-Service über das Web oder dem Test Runner zur Verfügung. Eine an den Dashboard-Service angelehnte kostenlose Open-Source-Version stellt der Cloud-Service Sorry Cypress zur Verfügung.Ein Klick auf die Log in-Schaltfläche in der Toolbar des Test Runners führt die Anmeldung im Cypress-Benutzeraccount durch. Unterhalb der Toolbar des Test Runners befindet sich das Register Runs, wählt man dieses aus, so kann man über Connect to Dashboard eine Verbindung zum Dashboard-Service aufbauen. Im Bedarfsfall definiert man anschließend ein neues Projekt; oder das Dashboard zeigt die projectID eines bereits bestehenden Projekts zusammen mit dem für dessen Ausführung notwendigen cypress run-Befehl an. Dieser cypress run-Befehl mit den beiden Parameter --record und --key eignet sich auch für die Ausführung von Tests in der eingesetzten CI/Continuous Integration-Umgebung.Eine CI-Umgebung setzt man im Rahmen der agilen Software-Entwicklung für den automatischen Build der Web-App ein. Das CI-Werkzeug zusammen mit dem Änderungs- und Versionierungstool erlaubt eine kontinuierliche automatische Bereitstellung der Software. Dabei ermöglicht das Cypress Dashboard die automatische Ausführung von Testfällen während dem Build der Web-App. Dabei unterstützt Cypress auch die parallele Ausführung von Testfällen. Zudem verfügt das Dashboard über eine größere Anzahl von Auswertungsfunktionen und Statistiken, die man mit dem Protokoll der Testausführung und den Testfällen ausführen und einsehen kann.Seit Frühjahr 2021 enthält Cypress mit der Version 7 einen Component Test Runner, der sich derzeit im Alpha-Status befindet. Im Unterschied zu einer Web-App stellen Komponenten wiederverwendbare Bausteine dar. Je weniger Abhängigkeiten eine Komponente besitzt, um so öfter und leichter lässt sie sich wiederverwenden. Der in Cypress integrierte Component Test Runner führt Component Tests angelehnt an den Cypress Test Runner im Webbrowser aus. Dabei stehen alle Cypress-Befehle zur Verfügung. Component Testing unterstützt auch ein Mocking der Netzwerkebene mittels des cy.intercept-Befehls.Grundsätzlich benötigt man für Component Testing in der Konfigurationsdatei von Cypress (cypress.json) einen component-Schlüssel, der auf die Testfälle über testFiles und auf den Quellcode der Componenten über componentFolder verweist:
{
"component": {
"testFiles": "**/*.test.{js,ts,jsx,tsx}",
"componentFolder": "src/components"
}
}
Das Testen einer Webkomponente erfolgt immer in einer speziellen, isolierten Umgebung – einem virtualisierten Webbrowser (jsdom genannt). Im Falle von Cypress entspricht der Component Test Runner dieser Testumgebung für Komponenten; er kommt zusammen mit dem im Hintergrund laufenden webpack-dev-server zum Einsatz. Die zugehörige Schnittstelle installiert man als dev-Abhängigkeit über das npm-Package @cypress/webpack-dev-server in den Projektordner zusammen mit @cypress/react für eine React- oder @cypress/vue@next für eine Vue-App. Zusätzlich müssen noch die in @cypress/react oder @cypress/vue@next enthaltenen Plugins über cypress/plugins/index.js-Datei für den webpack-dev-server geladen werden:
const { startDevServer } = require
('@cypress/webpack-dev-server')
const webpackConfig = require
('@vue/cli-service/webpack.config.js')
module.exports = (on, config) => {
on('dev-server:start', options =>
startDevServer({options, webpackConfig}) )
return config
}
Im Unterschied zum User-Interface-Testing mit Cypress bei dem ein cy.visit()-Befehl die Web-App aktiviert, startet das Component-Testing immer über einen mount-Befehl. Dabei lehnt sich der mount-Befehl bei einer React-App an die render()-Methode von React und im Falle einer Vue-App an die mount()-Methode von Vue.js an.Danach stehen alle Methoden der React- beziehungsweise Vue-Komponente zum Testen bereit und können in den Cypress Component-Tests verwendet werden. Beim Schreiben dieser Component-Tests verwendet man wie üblich die BDD-Syntax mit Assertions.
Links zum Thema
<b>◼ <a href="https://ionicframework.com/" rel="noopener" target="_blank">Homepage von Ionic</a> <br/></b>