
Wenn Sie Schnittstellen in React oder anderen Frameworks entwickeln FrontendFrüher oder später merkt man, dass es riskant ist, sich allein auf „Es funktioniert auf meinem Rechner“ zu verlassen. Eine kleine Änderung an einer Komponente, ein schnelles Refactoring oder eine aktualisierte Abhängigkeit können Teile der Anwendung lahmlegen, ohne dass man es überhaupt merkt … Es sei denn, man hat … Ein gut eingerichtetes Unit-Testing-System mit Jest.
Das moderne JavaScript-Ökosystem hat automatisierte Tests in seiner DNA. Tools wie ist Sie machen Schreiben Sie Tests für die KomponenteDie Verwendung von Funktionen und Hooks sollte sich problemlos in den Arbeitsalltag integrieren lassen, selbst wenn Sie kein Testfanatiker sind. Wichtig ist eine komfortable Umgebung, das Verständnis für das Schreiben von Tests und die Fähigkeit, die Ergebnisse und die Testabdeckung zu interpretieren, um ungetestete Bereiche Ihres Codes zu identifizieren.
Warum Unit-Tests in Frontend-Projekten?
Unit-Tests sind kleine Tests, die bestimmte Teile Ihres Codes überprüfen. (Funktionen, Komponenten, Hooks, Hilfsfunktionen usw.). In der Frontend-Entwicklung sind sie besonders nützlich, da sich die Benutzeroberfläche häufig ändert, Zustandslogik, Benutzerereignisse, asynchrone Aufrufe usw. vorhanden sind. Ohne ein Sicherheitsnetz ist jede Änderung ein Glücksspiel.
Zu den deutlichsten Vorteilen von Unit-Tests gehören die Frühe FehlererkennungAnstatt Fehler erst dann zu entdecken, wenn der Benutzer bereits produktiv arbeitet, werden sie erkannt, sobald Änderungen gespeichert und die Testsuite ausgeführt wird. Dies hilft Ihnen, die Funktionsweise besser zu verstehen. Lebenszyklus des FehlersDas spart dem Team Zeit, Geld und eine Menge Ärger.
Ein weiterer sehr wichtiger Punkt ist, dass Die Tests fungieren letztendlich als lebendige Dokumentation.Die Analyse der Testlogik einer Komponente oder Funktion verdeutlicht deren erwartete Verwendung, die akzeptierten Eingaben und die zu erwartenden Ergebnisse. In großen Projekten ist dies für neue Teammitglieder von unschätzbarem Wert.
Im Kontext von JavaScript und React, Das Schreiben von Tests trägt außerdem zu einer besseren Modularisierung des Codes bei.Um ein einzelnes Element separat testen zu können, muss es gut isoliert sein, mit klaren Abhängigkeiten und definierten Verantwortlichkeiten. Dies führt mittel- und langfristig zu einem besser wartbaren Frontend.
Was ist Jest und warum wird es so häufig in der Frontend-Entwicklung eingesetzt?
Jest ist ein JavaScript-Testframework, das ursprünglich von Facebook entwickelt wurde., wurde für die optimale Zusammenarbeit mit React entwickelt, ist aber auch für jedes client- oder serverseitige JavaScript- oder TypeScript-Projekt bestens geeignet.
Einer seiner größten Vorteile ist die Philosophie der „Nullkonfiguration“In vielen Projekten genügt es, das Programm zu installieren und ein Skript zur package.json-Datei hinzuzufügen, um Tests auszuführen, ohne sich in komplexen Konfigurationsdateien zu verlieren. Dies macht es besonders attraktiv für Frontend-Umgebungen, in denen bereits viele Tools im Einsatz sind.
Jest integriert sich standardmäßig. Hauptmerkmale für Frontend-ProjekteSchnelle Testausführung, Überwachungsmodus, der Tests bei Erkennung von Änderungen erneut ausführt, sehr komfortable Unterstützung für asynchronen Code, Mocks und Spies zur Simulation von Abhängigkeiten sowie Generierung von Codeabdeckungsberichten ohne Verwendung zusätzlicher externer Tools.
Bei Frontend-Projekten mit React wird Jest fast immer mit … kombiniert. ReaktionstestbibliothekDiese Bibliothek vereinfacht das Testen von Komponenten anhand ihres Verhaltens und ihrer Darstellung, anstatt sich zu sehr auf die interne Implementierung zu konzentrieren. Mit diesen beiden Tools lassen sich praktisch alle üblichen Anforderungen an Schnittstellentests abdecken.
Installation der Jest- und React-Testbibliothek in einem Frontend-Projekt
Der erste Schritt beim Einstieg in Jest besteht darin, es als Entwicklungsabhängigkeit hinzuzufügen. in Ihrem Projekt. Wenn Sie npm verwenden, lautet der typische Befehl:
npm install --save-dev jest
Wenn Sie lieber mit Garn arbeiten möchtenSie können es installieren mit:
yarn add --dev jest
In React-basierten Projekten ist es sehr üblich, auch die React Testing Library zu installieren., das aus mehreren Paketen besteht: der Basis @testing-library/react für Komponenten, @testing-library/jest-dom für zusätzliche Matcher auf dem DOM und oft @testing-library/user-event zur Simulation komplexer Benutzerinteraktionen.
Ein typisches React-Setup könnte etwa so aussehen::
npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event
Nachdem diese Abhängigkeiten eingerichtet sind, ist Ihre Umgebung bereit, komponentenorientierte Unit-Tests zu schreiben.Ereignisse und Ergebnisse, die für den Benutzer sichtbar sind, wobei Jest stets als Haupt-Testausführungs-Engine dient.
Grundlegende Jest-Konfiguration in package.json
Sobald Jest installiert ist, müssen Sie dem Projekt mitteilen, wie die Tests gestartet werden.Üblicherweise fügt man der package.json-Datei ein Skript hinzu, um einen einfachen Befehl über das Terminal ausführen zu können.
Ein minimales Beispiel für eine Konfiguration könnte sein:
{ «scripts»: { «test»: «jest» } }
Mit diesem Skript können Sie alle Projekttests durch einfaches Starten ausführen.:
npm Test
oder, falls Sie Garn verwenden, mit:
Garntest
Jest erkennt Testdateien automatisch anhand ihres NamensStandardmäßig sucht das Programm in Ihrer Ordnerstruktur nach Dateien mit den Endungen .test.js oder .spec.js, sodass Sie normalerweise keine Pfade manuell angeben müssen, solange Sie diese Konventionen beachten.
Dateikonvention: Dateiendung .test.js und Teststruktur
Damit Jest Ihre Tests ohne zusätzliche Konfiguration erkennt, Es wird dringend empfohlen, die .test.js-Erweiterung zu verwenden. (oder .test.ts, falls Sie mit TypeScript arbeiten). Wenn Sie beispielsweise eine Button.jsx-Komponente haben, wäre ein üblicher Name für deren Test Button.test.js, entweder im selben Verzeichnis oder in einem separaten Ordner „tests“.
Diese Konvention hat zwei klare Vorteile:
- Zum einen findet Jest automatisch die auszuführenden Dateien.
- Andererseits weiß jeder, der neu im Projekt ist, sofort, welche Dateien den Produktionscode und welche die Tests enthalten.
Die Tests werden definiert durch die Testfunktion oder ihr AliasDas erste Argument ist eine Textbeschreibung dessen, was geprüft werden soll, und das zweite eine Funktion, die die Testlogik ausführt. Innerhalb dieser Funktion werden Assertions mithilfe von `expect` und dessen verschiedenen Matchern verwendet.
In React-Komponenten ist die Struktur ähnlich.Anstatt eine reine Funktion zu testen, rendert man die Komponente mit der React Testing Library, sucht nach Elementen auf dem Bildschirm (nach Text, Rolle, Beschriftungen usw.) und prüft, ob sie angezeigt werden oder wie erwartet reagieren, wenn Benutzerinteraktionen simuliert werden.
Schreiben Sie Ihren ersten Unit-Test mit Jest.
Um das Ganze auf die Realität herunterzubrechen, Stellen Sie sich eine einfache Funktion vor, die zwei Werte addiert.Definieren Sie in einer Datei namens sum.js die Funktion sum(a, b) { return a + b; } und exportieren Sie diese. Importieren Sie anschließend in sum.test.js diese Funktion und definieren Sie einen Test mit einer klaren Beschreibung des erwarteten Ergebnisses.
Der Testkörper beschränkt sich darauf, die Funktion auszuführen und das Ergebnis zu validieren.Sie rufen sum(1, 2) auf und verwenden expect, um anzugeben, dass der Wert genau 3 sein muss. Wenn die Funktion dieses Ergebnis nicht mehr zurückgibt (aufgrund eines Fehlers oder einer unvorhergesehenen Änderung), markiert Jest den Test als fehlgeschlagen.
Diese Art von Test, so einfach er auch erscheinen mag, ist die Grundlage für Unit-Tests.Jede Funktion bzw. logische Einheit verfügt über einen oder mehrere Tests, die beschreiben, wie sie sich in verschiedenen Szenarien verhalten soll, sodass jede Abweichung vom erwarteten Verhalten durch einfaches Ausführen der Testsuite sofort erkennbar wird.
Bei Frontend-Komponenten ist der Ansatz genauso unkompliziert.Sie rendern die Komponente, prüfen, was angezeigt wird, simulieren Ereignisse wie Klicks oder Eingaben und validieren, dass der resultierende Zustand und das DOM dem funktionalen Design der Anwendung entsprechen.
Mit dem Wachstum des Projekts werden Sie Hinzufügung weiterer Tests zur Abdeckung von Grenzfällenatypische Einträge, Fehler und weniger offensichtliche Situationen werden erkannt, wodurch die Zuverlässigkeit der Anwendung gestärkt und Regressionen bei der Einführung neuer Funktionen verhindert werden.
Jest Matchers: Verschiedene Möglichkeiten zur Überprüfung der Ergebnisse
Der Kern der Behauptungen in Jest ist die ErwartungsfunktionDiese Funktion wird mit verschiedenen Matchern verkettet, um die Anforderungen an den empfangenen Wert festzulegen. Je nachdem, was Sie testen, verwenden Sie den einen oder anderen Matcher. Dies sind die praktischsten Matcher:
- zu sein. Es prüft auf strikte Gleichheit, was in JavaScript bedeutet, dass Wert und Typ übereinstimmen müssen. Dies ist besonders nützlich für Zahlen, Zeichenketten oder boolesche Werte, bei denen eine exakte Übereinstimmung erwartet wird. Wenn Sie beispielsweise den Wert 3 erwarten, soll nicht einfach nur „3“ zurückgegeben werden.
- gleichNützlich bei der Arbeit mit Objekten oder Arrays. Dieser Matcher vergleicht die Struktur und den Inhalt von Objekten, sodass Sie überprüfen können, ob eine Funktion ein Objekt mit den korrekten Eigenschaften und Werten zurückgibt, selbst wenn die interne Referenz nicht übereinstimmt.
- nicht. Wenn Sie zu irgendeinem Zeitpunkt sicherstellen müssen, dass etwas NICHT passiert, können Sie die Negation `not` verwenden. Beispielsweise macht `expect(value).not.toBe(0)` deutlich, dass eine Zahl nicht null sein darf, oder `expect(array).not.toEqual([])` zeigt an, dass Sie kein leeres Array erwarten.
Zusätzlich zu diesen Grundlagen bietet Jest viele weitere Funktionen. andere Heiratsvermittler: um zu überprüfen, ob eine Funktion einen Fehler auslöst, ob ein Array ein bestimmtes Element enthält, ob eine Zeichenkette einem regulären Ausdruck entspricht oder, im Falle von React mit jest-dom, ob ein DOM-Element sichtbar oder deaktiviert ist, einen bestimmten Text enthält usw.
Asynchrones Testen in Jest: Promises, async/await und Callbacks
Das moderne Frontend ist voll von asynchrone OperationenHTTP-Anfragen, Timer, Benutzerinteraktionen, die Zustandsaktualisierungen auslösen usw. Deshalb integriert Jest verschiedene Möglichkeiten, um komfortabel mit asynchronen Tests zu arbeiten.
Die sauberste und gebräuchlichste Methode zum Testen asynchroner Logik ist Verwende async/awaitSie deklarieren Ihre Testfunktion als asynchron, warten, bis das zu prüfende Promise aufgelöst ist, und führen dann die üblichen Assertions mit expect auf dem empfangenen Ergebnis durch.
Beispielsweise könnten Sie eine fetchData-Funktion haben, die ein Promise zurückgibt, und einen asynchronen Test schreiben, der fetchData aufruft, auf dessen Auflösung wartet und überprüft, ob die zurückgegebenen Daten Ihren Erwartungen entsprechen, sei es ein bestimmter Text oder ein Objekt mit einer bestimmten Struktur.
Jest unterstützt Promises auch direkt ohne async/await.Die Promise wird vom Test zurückgegeben, damit das Framework weiß, wann der Vorgang abgeschlossen ist. In älteren oder sehr speziellen Fällen ermöglicht dies außerdem die Verwendung von Callback-Funktionen mit einem `done`-Parameter, um das Testende zu signalisieren.
Im Bereich der React-Testbibliothek, Asynchrone Tests kombinieren häufig Wartebefehle mit findBy oder waitFor., die es ermöglichen, auf die Aktualisierung des DOM nach einer Anfrage oder einer Zustandsänderung zu warten, bevor die entsprechenden Aussagen getroffen werden.
Mocking in Jest: Simulieren von Modulen, Funktionen und Abhängigkeiten
Ein Grundprinzip des Unit-Testings ist Isolieren Sie die zu prüfende Einheit.Das bedeutet, dass Sie, wenn eine Funktion oder Komponente von externen Diensten (APIs, Drittanbieterbibliotheken, umfangreichen Modulen usw.) abhängt, diese Verhaltensweisen simulieren sollten, anstatt sie während des Tests tatsächlich auszuführen.
Jest erleichtert diese Isolation durch Simulationen.Mit jest.fn lassen sich Mock-Funktionen erstellen, die protokollieren, wie oft sie aufgerufen werden, mit welchen Argumenten sie übergeben werden und welchen Wert sie zurückgeben sollen. Dies ist sehr nützlich, um interne Interaktionen zu testen, ohne den eigentlichen Code der betroffenen Dienste verändern zu müssen.
Wenn Sie noch einen Schritt weiter gehen müssen, Mit jest.mock können Sie ganze Module ersetzen.Sie können festlegen, dass Jest beim Importieren einer bestimmten Datei eine Dummy-Implementierung verwenden soll, die kontrollierte Werte zurückgibt, um beispielsweise zu vermeiden, dass bei jedem Ausführen der Testsuite echte HTTP-Anfragen gesendet werden.
In React-Komponenten werden Mocks häufig verwendet, um benutzerdefinierte Hooks zu simulieren., Datendienste oder Module, die lokale Speicherung, Analysen usw. verwalten, wobei der Test sich auf das Verhalten der Komponente und nicht auf das ihrer externen Abhängigkeiten konzentriert.
Bei sachgemäßer Anwendung, Mocking beschleunigt die Testausführung erheblich. und ermöglicht es Ihnen, Fehlerszenarien, ungewöhnliche Serverantworten oder atypische Zustände, die durch die Interaktion mit realen Diensten nur schwer zu erreichen wären, einfach zu reproduzieren.
Das Organisieren und Gruppieren von Tests mit Blöcken beschreibt
Wenn Ihre Testsuite wächst, benötigen Sie einen Mindestbestand aufrechterhalten Um nicht den Überblick über Hunderte von Tests zu verlieren, die über mehrere Dateien verteilt sind, bietet Jest Blöcke als natürliche Möglichkeit, zusammengehörige Tests zu gruppieren.
Mit „beschreiben“ können Sie mehrere Tests im selben Kontext einschließenZum Beispiel „arithmetische Operationen“ oder „Verhalten der Header-Komponente“. Innerhalb des Blocks beschreibt jeder Test einen spezifischen Fall, aber die gesamte Testreihe liest sich wie eine zusammenhängende Geschichte über diesen Teil des Codes.
Diese Organisation hilft sowohl beim Lesen als auch beim Debuggen.Wenn etwas schiefgeht, ist es einfacher, die Testgruppe zu finden und zu verstehen, welcher Teil des Systems betroffen ist, ohne das gesamte Projekt durchsuchen zu müssen.
Zusätzlich beschreibt und lässt sich sehr gut mit den Jest-Lifecycle-Hooks kombinieren.Funktionen wie beforeEach oder afterEach ermöglichen es Ihnen, Daten vorzubereiten oder gemeinsame Zustände für alle Tests innerhalb desselben Blocks zu löschen, wodurch die Duplizierung der Initialisierungslogik in jedem einzelnen Test vermieden wird.
In komplexen Frontend-Projekten ist es üblich, für jede Komponente eine eigene Beschreibung zu haben., gegebenenfalls unterteilt in interne Beschreibungen für verschiedene Modi, Eigenschaften oder Interaktionsabläufe, wodurch die Testdatei zu einer ziemlich klaren Übersicht über alles wird, was von dieser Komponente erwartet wird.
Verwendung von npm-Tests und Ausführungsdisziplin im Workflow
Nachdem die Basiskonfiguration abgeschlossen ist, Der npm-Testbefehl wird zu Ihrem täglichen VerbündetenDas Ausführen des Linters vor dem Hochladen der Änderungen sollte eine nahezu automatische Handlung sein, ähnlich wie das Speichern der Datei oder das Ausführen des Linters.
Viele Teams befolgen die ungeschriebene Regel, dass man sich nicht festlegt, wenn die Tests fehlschlagen.Durch diese Vorgehensweise wird verhindert, dass der Hauptzweig des Projekts beschädigt wird, und eine garantierte Mindestqualität bei jedem Merge oder Pull Request, der in das Repository integriert wird, wird sichergestellt.
Jest bietet außerdem an ein sehr nützlicher interaktiver Modus befindet sich in der EntwicklungDurch die Ausführung von npm test im Watch-Modus führt das Framework nur die Tests erneut aus, die sich auf die geänderten Dateien beziehen. Dies beschleunigt den Test- und Fehlerbehebungszyklus erheblich, während Sie neue Funktionen entwickeln oder Fehler beheben.
Integration von Jest in ein Continuous-Integration-System (CI) als GitHub-Aktionen Den Kreis schließenJedes Mal, wenn jemand Code in das Remote-Repository hochlädt, führt der CI-Server npm test aus und blockiert die Integration, falls die Testsuite fehlschlägt, um zu verhindern, dass Fehler in gemeinsam genutzte Umgebungen gelangen.
Codeabdeckung: Messung, wie viel tatsächlich getestet wird
Schriftliche Prüfungen reichen nicht aus. Interessant ist auch, inwieweit sie den Code abdecken.Zu diesem Zweck integriert Jest ein Coverage-Reporting, das angibt, welche Zeilen, Funktionen und Zweige während des Testens ausgeführt wurden.
Das Generieren dieser Berichte ist so einfach wie das Hinzufügen des Parameters --coverage zum Testbefehl.Beispielsweise können Sie das package.json-Skript wie folgt konfigurieren: "test": "jest --coverage" oder npm test --coverage ausführen, wenn Sie einen detaillierten Bericht wünschen.
Das Ergebnis umfasst Abdeckungsprozentsätze pro Datei und auf globaler EbeneSie werden sehen, welche Dateien eine gute Testabdeckung aufweisen und welche während der Tests kaum berücksichtigt werden. Dies hilft Ihnen zu entscheiden, wo es sich lohnt, zusätzlichen Aufwand in das Schreiben weiterer Tests zu investieren.
Natürlich ist es wichtig, sich daran zu erinnern, dass Eine hundertprozentige Abdeckung garantiert nicht die Fehlerfreiheit.Es ist möglich, alle Codezeilen mit anspruchslosen Tests auszuführen, daher ist die Qualität der Assertions genauso wichtig wie, wenn nicht sogar wichtiger als die Anzahl selbst.
Nutzen Sie die Codeabdeckung als groben Indikator, zusammen mit Code-Reviews und gesundem Menschenverstand.Das ist eine gute Möglichkeit, ein Gleichgewicht zwischen Testaufwand und tatsächlichem Nutzen für die Projektstabilität zu wahren.
Mit allem gesehen, Verwendung von Jest und Tools wie der React Testing Library in Frontend-Projekten Es wird somit zu einer durchaus logischen Entscheidung.Es ermöglicht Ihnen zu überprüfen, ob jede Komponente und Funktion das tut, was sie soll, Tests einfach mit npm test auszuführen, die Codeabdeckung mit --coverage zu überwachen und eine solide Codebasis zu pflegen, in der es viel sicherer ist, das Produkt weiterzuentwickeln, ohne befürchten zu müssen, dass etwas, das bereits funktioniert, kaputt geht.



