Zurück zu Blogs
Blog Img

​End-to-End testen einer Echtzeit-Chat-Anwendung mit Cypress

Viele Experten sind der Meinung, dass Cypress das Testen deutlich vereinfacht. Gleb Bahmutov ist ein echter „JavaScript-Ninja“, der bei der Entwicklung von Cypress mitgeholfen hat. Er gab ein Webinar über das End-to-End-Testen einer Echtzeit-Chat-Webanwendung mit diesem JavaScript-Tool für Frontend-Testing. Eine Zusammenfassung.

Webanwendung basierend auf Socket.io

Wie kann man realistische End-to-End-Tests mit Cypress für eine Echtzeit-Chat-Anwendung durchführen? Diese Frage steht im Mittelpunkt der Onlinelesung von Gleb Bahmutov. Dieser „JavaScript-Ninja“ ist derzeit Senior Director of Engineering bei Mercari US, war zuvor VP of Engineering bei Cypress und hat in seiner Freizeit über 500 Blogbeiträge über Softwareentwicklung geschrieben.

In dem Webinar, dessen mit Code gefüllte Folien du dir hier ansehen kannst, behandelt er vier verschiedene Punkte, die alle eine andere Perspektive auf den Code geben: Mock-App-Code, Mock-Socket-Connection, offene zweite Socket-Connection und das Ausführen von zwei Testläufern. Bei der von Bahmutov besprochenen Anwendung handelt es sich um eine Webanwendung für Chats, die auf Socket.io basiert. Er hat den Code der Anwendung auf GitHub veröffentlicht.

Funktioniert die Anwendung?

Zunächst einmal wirft Bahmutov die Frage auf, ob die Anwendung funktioniert. „Man kann sie öffnen, aber Dinge gehen schnell kaputt. In Wirklichkeit musst du deshalb sowieso testen, und das kannst du am besten automatisiert tun. Deshalb schreiben wir heute einen Cypress-Test.“ Der JavaScript-Guru erklärt, dass ein typischer End-to-End-Test normalerweise dem folgenden Muster folgt: command – assertion(s) – command – assertion(s).

Weiter zum ersten Test. „In Cypress kannst du wirklich alles sehen, unter anderem etwa auch wie die Anwendung im echten Browser aussieht, den Benutzernamen und vieles mehr. Damit wir herausfinden können, ob die App auch tatsächlich funktioniert, müssen wir zunächst herausfinden, ob ein zweiter Nutzer im Chat meine Nachrichten sehen kann und umgekehrt. Schließlich könnte die Anwendung die Nachrichten spiegeln, diese jedoch nicht verschicken.“

Test-Assistenten

Bahmutov macht einen kleinen Abstecher: Er erklärt, dass das „Problem“ bei dieser Art von Test-Assistenten darin besteht, dass sie irgendwo eine Grenze ziehen müssen: welcher Teil wird also getestet und welcher nicht? Er fährt fort: „Von Cypress aus können wir uns mit einem Server von Socket.io verbinden und als zweiter Benutzer agieren. Ein normaler Test wird auf der Seite ausgeführt, ein anderer Teil des Codes gelangt zum Socket-Server und verhält sich wie ein zweiter Benutzer. Eine weitere Möglichkeit besteht darin, einen zusätzlichen Cypress Testläufer zu öffnen und zwei Browser miteinander kommunizieren zu lassen.“

Stub-Anwendungscode

„Wir beginnen mit etwas Einfachem: dem Stub-Anwendungscode. Du kannst eine Klasse oder ein Objekt im Anwendungscode erstellen. Dieses Anwendungsobjekt kannst du für den Test freigeben. Vom Test aus kannst du dann das Anwendungsobjekt beobachten und eingehende Nachrichten testen.“ Bahmutov zeigt, dass die App UI-Nachrichten anzeigt, die im Anwendungscode eingehen und die Seite dann die Nachrichten anzeigt.

Mock WebSocket

Es wurde nun bestätigt, dass der Anwendungscode bis zum Socket funktioniert. Die Socket-Befehle könnten jedoch fehlerhaft sein. „Um dies zu testen, kannst du ein Mock WebSocket verwenden. Dazu musst du den Prod-Websocket durch den Mock-Socket ersetzen. Bahmutov weist darauf hin, dass sich hier die Intercept-Funktionalität von Cypress als sehr nützlich erweist. Als nächstes injizieren wir den Mock-Socket in den iFrame der Anwendung. „Wir haben jetzt geprüft, ob die Socket-API innerhalb der Anwendung funktioniert. Beziehungsweise der UI-Code, der intermediäre Code und der WebSocket.“

Testen ob der Server funktioniert

Die Socket-API innerhalb der Anwendung kann funktionieren, es könnte jedoch auch sein, dass der Server defekt ist. „Während des Tests wollen wir die Seite überprüfen, durch die Benutzeroberfläche gehen und den zweiten, simulierten Benutzer verbinden. Dieser antwortet und“ hört die Nachrichten ab“, indem er sich mit demselben Server verbindet.“ Bahmutov erklärt, wie dies funktioniert, und gibt einen Tipp: „Verwende für den zweiten Benutzer eine Verbindung von außerhalb der Browserseite. Dies ist eine sauberere Methode, um eine zweite separate Verbindung mit dem Server herzustellen.“

Zwei Cypress-Instanzen zugleich ausführen

Wie kannst du zwei Cypress-Instanzen nebeneinander ausführen? Dazu sind zwei separate Spezifikationen erforderlich, die beide ausschließlich über die Benutzeroberfläche der Seite funktionieren. Der Test-Experte erklärt weiter, dass wir dazu wahrscheinlich separate Cypress-Konfigurationsdateien erstellen müssen, da wir zwei Instanzen gleichzeitig ausführen. Auch das NPM-Modul muss gleichzeitig installiert werden.

Nach Ansicht von Bahmutov weist diese Methode auf den ersten Blick eine Reihe von Mängeln auf. So warten die Prüfstellen von Cypress beispielsweise nicht wirklich aufeinander, sondern arbeiten unabhängig voneinander. Du möchtest demnach steuern können, wie die beiden Testläufer den Test durchführen. Um die Testläufer zu synchronisieren, kannst du eine separate Socket.io erstellen. Dazu musst du nur zwei Commands implementieren: „checkpoint“ und „wait for checkpoint“. Danach musst du den Server von Socket.io synchronisieren und die Cypress-Plugin-Datei implementieren.

Der erste und der zweite Testläufer

Bahmutov erklärt, dass der erste Testläufer die Seite besucht, den Namen festlegt und den Server checkt, woraufhin der erste Benutzer dem Chat beitritt. Jetzt muss der zweite Benutzer zum Chat hinzugefügt werden. Es wird dann auf den Checkpoint gewartet. Dieser prüft, ob der zweite Benutzer hinzugefügt wurde. Danach wird im ersten Testläufer überprüft, ob der zweite Benutzer auch tatsächlich vorhanden ist. Dieser muss dann eine Nachricht posten, damit du sehen kannst, ob die Nachricht sichtbar ist.

In der zweiten Spezifikationsdatei steht, dass der erste Benutzer zuerst den Checkpoint erreichen muss. Anschließend wird überprüft, ob die Nachricht vom ersten Benutzer stammt; der erste Testläufer wartet auf diesen Checkpoint. So sieht, kurz gefasst, die erste Testrunde aus. Bahmutov: „Mit anderen Worten: erst startet er, dann wartet er, dann kommen die Nachrichten aus der zweiten Testrunde, dann wird er verbunden, dann wartet er und dann wird die Nachricht schnell kommuniziert. Bei der zweiten Testrunde geht es viel schneller: er wird angeschlossen, Checkpoint, Nachricht gesehen und fertig. Die beiden Testläufer kommunizieren ständig miteinander und warten aufeinander, um sicherzustellen, dass alles in der richtigen Reihenfolge abläuft.“

Fazit: Was ist besser?

„Und was ist nun besser“? Mit dieser Frage schließt Bahmutov sein Webinar ab. „Ich habe vier verschiedene Möglichkeiten zum Testen von Code gezeigt: Stub-App-Code, Websocket-Mocking, damit du nie einen Server von Socket.io aus starten musst, das Agieren als zweiter Benutzer über eine Verbindung zu Socket.io, die von der Seite isoliert ist, und schließlich das Ausführen von zwei Testläufern nebeneinander, wobei ebenfalls wie ein zweiter Benutzer agiert wird. Meiner Meinung nach ist es viel besser, als zweiter Benutzer zu agieren, ohne den vollständigen Testlauf zu starten. Das ist nämlich ein vollständiger End-to-End-Test.“

„Der zweite Browser kommuniziert genauso, wie wir es über eine Verbindung mit Socket.io tun würden. Wir kommunizieren nur über eine öffentliche API und haben nichts vorrangig getan, da dies nicht notwendig war. Außerdem ist der Test immer noch sehr schnell“, so Bahmutov. „Weniger als zwei Sekunden, um auf beiden Seiten eine Verbindung herzustellen, die Seite zu laden, ein paar Nachrichten auszutauschen und schließlich zu bestätigen, dass der Socket-Server funktioniert, die Seite angezeigt wird und die Seite etwas sendet. Daher ist dies meine bevorzugte Methode, um Echtzeit-Chat-Anwendungen zu testen.“

Mehr lesen?

Möchtest du dich weiter in das Thema vertiefen? Bahmutov hat drei Blogbeiträge (auf Englisch) verfasst, die sich ausführlich mit diesem Thema auseinandersetzen: Testen einer socket.io Chat-App mit Cypress, Ausführen von zwei Cypress Testläufern zur gleichen Zeit und Synchronisieren von zwei Cypress-Läufern über Prüfpunkte.