Sie drücken eine kleine UI-Änderung vor dem Mittagessen aus. Sie sieht harmlos aus. Eine Schaltbeschriftung ändert sich, eine bedingte Renderung wird vereinfacht und ein Hilfs-Hook nimmt eine neue Zweigstruktur auf. Der Pull-Request ist sauber, die Überprüfung ist schnell und der Deploy geht raus.
Eine Stunde später meldet sich der Support, dass sich das Login auf einer Plattform nicht mehr funktioniert. Web sieht gut aus. Die Desktop-Shell hat einen veralteten Render-Pfad. Die mobile Build verhält sich anders nach einem asynchronen Zustandswechsel. Niemand hat es bemerkt, weil die code Tests hatten, aber nicht die richtigen Tests und definitiv kein zuverlässiges System um diese Tests herum.
Das ist das Hauptproblem bei der Einheitstestung von React in Produktivteams. Ein paar erfolgreiche Tests zu schreiben ist nicht schwer. Ein Suite aufzubauen, die dich auch während von Refaktorisierungen, Release-Trainings, Hotfixes und Cross-Plattform-Packagings schützt, ist die schwierige Sache. React-Apps scheitern nicht, weil ein Team vergessen hat, wie man eine Funktion aufruft render()Sie scheitern, weil sich die Tests in Richtung Implementierungsdetails bewegen, asynchrone Verhaltensweisen überdeckt werden und CI das Testen wie ein Kästchen anstelle eines Release-Gates behandelt
Moderne Einheitstestung von React funktioniert, wenn sie wie ein Sicherheitssystem funktioniert. Schnelle Feedbacks lokal. Deterministische Überprüfungen in CI. Klares Abgrenzen umzu, was in einem Einheitstest gehört und was nicht. Das ist noch wichtiger, wenn die gleiche React-Codebasis über Browser, Capacitor-Container oder Electron-Hüllen verschickt wird
Inhaltsverzeichnis
- Wenn Einheitstestung von React Dein bester Sicherheitsnetz ist
- Einrichten Sie Ihr modernes Testumfeld für React
- Schreiben Sie bedeutungsvolle Komponententests
- Testen Sie benutzerdefinierte Hooks und Anwendungslogik
- Fortgeschrittene Techniken meistern: Mocking und Async
- Die Testqualität und Strategie verbessern
- Integrieren von Tests in eine CI/CD Pipeline für Cross-Platform-Anwendungen
Weshalb Unit-Testing in React Ihr bester Sicherheitsnetz ist
Einheitstests verdienen ihren Preis, wenn sie den Fehler fangen, den Sie sich nicht vorstellen konnten. In React bedeutet das normalerweise, dass ein Komponente weiterhin renderet, aber das von den Benutzern abhängige Verhalten geändert wurde. Ein deaktiver Button wird klickbar. Ein Ladezustand wird nie gelöscht. Ein Fallback-Nachricht verschwindet nach einem Refaktor. Diese Fehler sind klein in code und teuer in der Produktion.
Das React-Testing wurde in einer wichtigen Weise, als React Testing Library zum mainstream-Modell für das Testen von Verhalten anstatt von Interna wurde, die Teams dazu drängte, Tests zu schreiben, die das Benutzer-Verhalten widerspiegeln, anstatt Komponenten-Props oder -State, wie im React Native-Testing-Leitfaden auf React Native testing overviewbeschrieben ist. Diese Veränderung ist wichtig, weil React code ständig umgebaut wird. Hooks werden verschoben. Komponenten werden geteilt. Context wird eingeführt. Ein Test, der an der internen Struktur gebunden ist, bricht während gesunder Refaktoren. Ein Test, der an sichtbarem Verhalten gebunden ist, überlebt normalerweise.
Was sollte ein Einheitstest schützen
Ein guter React-Einheitstest schützt einen kleinen Vertrag:
- Ausgegebene Ausgabe: Sieht der Benutzer das richtige Text, Label, Zustand oder Fallback?
- Interaktionsverhalten: Klickt, tippt oder schaltet sich der Benutzer korrekt auf die UI um?
- Grenzverhalten: Verhält sich das Komponente korrekt, wenn sie erwartete Eingaben, fehlende Daten oder einen Fehlerpfad erhält?
Ein schwacher Test schützt das falsche Ding:
- Komponenteninternes: Zustandsform, private Methoden, implementierungsbezogene Props
- Framework-Mechaniken: Wenn React eine Hook-Update intern genau so durchführte, wie Sie es erwartet haben
- Kindereigenschaften: Markup, das von nicht intendierten, verschachtelten Komponenten besessen wird
Praktische Regel: Wenn Sie das Komponenten ohne Änderung des Benutzererlebnisses oder der Benutzereingaben neu anordnen können, sollte der Test auch nicht geändert werden.
Einheiten-Tests befinden sich in einem umfassenderen Testsystem. Sie versuchen nicht, die gesamte Anwendung von Anfang bis Ende zu beweisen. Sie sind die schnelle Schicht, die Regressionsfehler vor der Notwendigkeit eines Browser- oder Geräte-Level-Validierungspasses aufgreift. Deshalb sind sie die erste Verteidigungslinie in jedem vernünftigen Stacks von Automatisierten Tests für Produktionsanwendungen.
Für React-Teams, die häufig liefern, kommt der Vertrauen durch diese Aufteilung der Arbeit. Einheiten-Tests fangen lokale Regressionsfehler schnell auf. Integrationstests überprüfen die Verbindungen. End-to-End-Tests bestätigen die kritischen Wege. Wenn Sie die Einheits-Schicht auslassen, muss alles langsamer unten zu viel Last tragen.
Einrichten Ihres modernen React-Testumfelds
Ein brüchiges Testumfeld schafft flache Tests, bevor Sie eine einzige Behauptung geschrieben haben. Viele Entwickler beschuldigen Jest, jsdom oder React, wenn das zugrunde liegende Problem eine inkonsistente Konfiguration auf lokalen Maschinen und CI ist. Die Lösung besteht darin, das Umfeld langweilig zu machen. Langweilig ist gut hier.

Beginnen Sie mit einem vorhersehbaren Runner und Umfeld
Für eine moderne React-Anwendung, insbesondere eine mit Vite erstellt, sollte die Grundkonfiguration umfassen:
- Eine Testausführer: Jest bleibt gängig, insbesondere in älteren React-Codebasen und Unternehmens- CI-Stacks.
- Eine browserartige Umgebung:
jsdomlässt Komponententests DOM-Ausgaben rendern. - Werkzeuge von Testing Library:
@testing-library/reactund@testing-library/jest-dom - Eine einzelne Einrichtungseingabe: Ein Datei, um Matcher und globale Mocks zu registrieren
Die wichtigste Arbeitsweise, die die Testleitlinien von React unterstreichen, ist einfach: Das Komponentenrendern in einer jsdom-gestützten Umgebung, die UI-Abfrage mit Selektoren wie getByText oder getByRole, die Interaktion auslösen und die DOM-Änderung überprüfen, wie in der beschriebenen React-TestdokumentationEin solches Workflow bleibt nur dann vertrauenswürdig, wenn alle Maschinen das gleiche Testumfeld laufen.
Ein praktischer Jest-Einrichtung sieht normalerweise so aus:
// jest.config.js
module.exports = {
testEnvironment: 'jsdom',
setupFilesAfterEnv: ['<rootDir>/src/setupTests.js'],
moduleNameMapper: {
'\\.(css|less|scss)$': 'identity-obj-proxy',
'^@/(.*)$': '<rootDir>/src/$1',
},
transform: {
'^.+\\.(js|jsx|ts|tsx)$': 'babel-jest',
},
};
Wenn Ihr Team stattdessen SWC anstatt Babel verwendet, ist das in Ordnung. Der Punkt ist nicht der Transformer. Der Punkt ist Konsistenz. Wählen Sie einen Weg und standardisieren Sie ihn im Repository. Wenn Sie eine gute Begleitdokumentation für umfassendere JavaScript-Testkonventionen wünschen, ist Capgo’s Ein Leitfaden für Einheitstests in JavaScript ist eine nützliche Dokumentation für Team-Übernahmen.
Hinzufügen Sie das Einrichtungsdatei, auf das Ihr Suite angewiesen ist
Ein ordnungsgemäßes setupTests.js erspart viel wiederholten Lärm:
import '@testing-library/jest-dom';
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
Dieses Datei ist, wo Sie Umgebungsunterschiede einmal statt in zwanzig Testdateien lösen. Fügen Sie Mocks für APIs hinzu, auf die Ihre UI angewiesen ist, wie z.B. matchMedia, ResizeObserver, oder IntersectionObserver, wenn Ihre Komponentenbibliothek sie erwartet.
Ohne das passieren unkoordinierte Tests und schwer zu verfolgende Fehler. Ein lokaler Lauf eines Entwicklers funktioniert, weil er eine manuelle Mock-Implementierung in einem Datei hinzugefügt hat. Der CI-Fehler tritt auf, weil die Einstellungen nicht geteilt wurden.
Behalten Sie die Lokal- und CI-Verhaltensweise in Einklang.
Die lokale Kommandozeilenanweisung sollte der CI-Kommandozeilenanweisung so nahe wie möglich entsprechen. Wenn Entwickler in Watch-Modus mit permissiven Einstellungen arbeiten, aber der CI eine strengere Konfiguration ausführt, erhalten Sie Überraschungsfehler nach dem Merge. Halten Sie Skripte explizit:
{
"scripts": {
"test": "jest",
"test:watch": "jest --watch",
"test:ci": "jest --runInBand --coverage"
}
}
Ein kurzer Leitfaden hilft neuen Teammitgliedern, sich schnell auf die gleiche Basis zu bringen:
Die wichtigste Einstellungswahl ist die Disziplin bei den Standards. Legen Sie Alias in der Konfiguration ab. Legen Sie Umgebungs-Mocks in einer Einstellungsdokumentation ab. Verwenden Sie jsdom für UI-Tests und einen leichten Umgebung für reine Utilities, wenn möglich. Je weniger individuelles Verhalten jeder einzelne Test benötigt, desto zuverlässiger wird Ihr System.
Schreiben Sie Bedeutungsvolle Komponenten-Tests
Organisationen haben kein Problem, Tests zu schreiben. Sie haben ein Problem, Tests zu schreiben, die nach sechs Monaten noch Bedeutung haben.
Die Standardmuster für die Einheitstests von React-Komponenten ist immer noch das richtige: rendern Sie die Komponente, überprüfen Sie die Benutzeroberfläche mit benutzerzentrierten Selektoren, lösen Sie eine Interaktion aus und bestätigen Sie den resultierenden DOM-Änderungen, die Tests von Implementierungsdetails wie Zustand oder Props fernhält, wie in der React-Testanleitung beschrieben. Das Geheimnis besteht darin, dieses Muster mit Zurückhaltung anzuwenden.
Testen Sie das Akkordeon wie ein Benutzer es verwendet
Nehmen Sie ein grundlegendes Komponenten. Es renderet einen Button mit einem Titel. Der Inhalt des Panels beginnt versteckt. Klicken Sie auf den Button, um den Inhalt zu enthüllen und die Barrierefreiheit zu aktualisieren. Accordion Das reicht für mehrere nützliche Tests aus:
Die Anfangsrendereihe zeigt den Titel, aber nicht den Inhalt.
- Klicken Sie auf den Trigger, um den Inhalt zu enthüllen.
- Klicken Sie erneut, um ihn zusammenzufalten.
- Die Barrierefreiheitseigenschaften spiegeln den sichtbaren Zustand wider.
- Dass letzte Punkt wird oft übersehen. Wenn Ihre Komponente ARIA-Attribute oder eine role-basierte Struktur verwendet, überprüfen Sie sie. Das sind keine Implementierungsdetails. Sie sind Teil des Benutzerfreundlichkeitsvertrags.
Die besten Komponententests lesen sich wie ein Fehlerbericht, den Sie nie erhalten möchten. aria-expanded, aria-controlsInitial render shows the title but not the content.__CAPGO_KEEP_0__
Clicking the trigger reveals the content.__CAPGO_KEEP_0__
Wählen Sie Abfragen basierend auf der Absicht
Die React Testing Library bietet Ihnen mehrere Abfragemuster, aber sie sind nicht austauschbar. Das falsche Muster macht die Tests laut oder irreführend.
| Abfrageart | Wenn das Element gefunden wird | Wenn das Element nicht gefunden wird | Beispiel für Verwendung |
|---|---|---|---|
getBy |
Gibt das Element sofort zurück | Gibt einen Fehler sofort aus | Behaupten Sie, dass ein Button oder ein Überschrift bereits auf dem Bildschirm ist |
queryBy |
Gibt das Element sofort zurück | Gibt zurück null |
Behaupten Sie, dass verstecktes Inhalt vor der Interaktion nicht existiert |
findBy |
Wird aufgelöst, wenn das Element erscheint | Nach einer Wartezeit abgelehnt wird | Behauptet, dass der async-geladene Inhalt nach einem Fetch oder einer verzögerten Aktualisierung erscheint |
Ein einfaches mentales Modell hilft:
- Verwende
getByfür Dinge, die bereits existieren müssen. - Verwende
queryByfür Dinge, die noch nicht existieren dürfen. - Verwende
findBywenn sich die Benutzeroberfläche später ändert.
Wenn ein Test mit findBy für alles beginnt, bedeutet es meistens, dass der Autor sich nicht sicher ist, wann der Komponenten aktualisiert wird. Diese Unsicherheit wird später zu Flakiness.
A praktische Akkordeon-Beispiel
Hier ist ein repräsentatives Komponenten-Beispiel:
function Accordion({ title, children }) {
const [open, setOpen] = React.useState(false);
return (
<section>
<button
aria-expanded={open}
aria-controls="accordion-panel"
onClick={() => setOpen(prev => !prev)}
>
{title}
</button>
{open ? (
<div id="accordion-panel">
{children}
</div>
) : null}
</section>
);
}
Und hier ist die Form der zu behaltenden Tests:
import { render, screen, fireEvent } from '@testing-library/react';
test('renders the accordion title and hides content initially', () => {
render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);
expect(screen.getByRole('button', { name: /shipping details/i })).toBeInTheDocument();
expect(screen.queryByText(/delivery takes 3 days/i)).not.toBeInTheDocument();
});
test('reveals content when the trigger is clicked', () => {
render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);
fireEvent.click(screen.getByRole('button', { name: /shipping details/i }));
expect(screen.getByText(/delivery takes 3 days/i)).toBeInTheDocument();
});
test('updates aria-expanded when opened', () => {
render(<Accordion title="Shipping details">Delivery takes 3 days</Accordion>);
const button = screen.getByRole('button', { name: /shipping details/i });
expect(button).toHaveAttribute('aria-expanded', 'false');
fireEvent.click(button);
expect(button).toHaveAttribute('aria-expanded', 'true');
});
Was fehlt ist genauso wichtig. Es gibt keine Behauptung gegen den internen Zustand. Keine Überprüfung, ob etwas aufgerufen wurde. Kein Snapshot des gesamten gerenderten Baumes. Diese Tests würden die Wartung erhöhen, nicht die Zuversicht. setOpen Eine paar Gewohnheiten machen die Komponententests stärker:
Präferieren Sie role-basierte Abfragen:
- Tasten, Überschriften, Dialoge, Warnungen und Eingabefelder sollten normalerweise über ihre Rolle gefunden werden. Behalten Sie jeden Test eng:
- Eine Benutzerinteraktion pro Test hält die Fehlerlesbarkeit aufrecht. Benennen Sie Tests nach den Ergebnissen:
- “aktualisiert aria-expanded, wenn geöffnet” ist viel nützlicher als “funktioniert richtig.” __CAPGO_KEEP_0__
If ein Komponente schwer zu testen ist, zeigt das oft ein Designproblem an. Vielleicht versteckt sie den Zustand an falschem Ort. Vielleicht fehlt es an semantischer Markierung. Gute Tests drängen Teams oft zu besseren Komponenten.
Testen von benutzerdefinierten Hooks und Anwendungslogik
React-Anwendungen verbergen eine Menge wichtiger Verhaltensweisen außerhalb von Komponenten. Zustandsübergänge leben in Hooks. Validierung und Formatierung leben in Hilfsfunktionen. Die Datenformierung findet oft vor dem ersten Rendering statt. Wenn Sie nur sichtbare Komponenten testen, werden Sie einen großen Teil der code übersehen, der den Produktionsverhalten noch brechen kann.
Hooks benötigen eine React-beauftragte Umgebung
Ein benutzerdefinierter Hook benötigt immer noch React, um korrekt zu funktionieren, daher testen Sie ihn mit renderHook und um den Zustand verändernde Aufrufe in act().
Ein kleiner useToggle Hook ist ein gutes Beispiel:
import { useState, useCallback } from 'react';
export function useToggle(initialValue = false) {
const [value, setValue] = useState(initialValue);
const toggle = useCallback(() => setValue(current => !current), []);
return { value, toggle };
}
Sein Test sollte sich auf den öffentlichen Vertrag konzentrieren:
import { renderHook, act } from '@testing-library/react';
import { useToggle } from './useToggle';
test('returns the initial value', () => {
const { result } = renderHook(() => useToggle(true));
expect(result.current.value).toBe(true);
});
test('toggles the value', () => {
const { result } = renderHook(() => useToggle(false));
act(() => {
result.current.toggle();
});
expect(result.current.value).toBe(true);
});
Dieser Test ist nützlich, weil der Hook selbst die Einheit ist. Sie testen nicht die React-Internen. Sie verifizieren das externe Verhalten des Hooks.
Für Produktteams, die wiederholbare UI oder Feature-Primitiven entwickeln, ist dieses Muster sehr wichtig. Hooks werden oft als Schnittstelle zwischen Apps, Design-Systemen oder internen Werkzeugen verwendet. Wenn Sie mit kommerziellem Zweck wiederholbare Verhaltensweisen entwickeln, sind die Ressourcen zu Hooks für Makers-Produkte Hilft Ihnen dabei, Hooks als produktisierte Bausteine anstatt nur als Implementierungsdetails zu betrachten.
Reine Logik sollte in Tests rein bleiben.
Alles benötigt nicht jsdom, React oder Testing Library. Wenn eine Funktion rein ist, testen Sie sie mit plain Jest in einem Node-Umgebung.
Beispiel:
export function formatDisplayName(firstName: string, lastName: string) {
return `${firstName.trim()} ${lastName.trim()}`.trim();
}
Dieser Test sollte extrem einfach sein:
import { formatDisplayName } from './formatDisplayName';
test('joins and trims both names', () => {
expect(formatDisplayName(' Ada ', ' Lovelace ')).toBe('Ada Lovelace');
});
test('handles a missing last name', () => {
expect(formatDisplayName('Ada', '')).toBe('Ada');
});
Der Gewinn hier ist Geschwindigkeit und Klarheit. Wenn eine Funktion kein renderiertes Baum benötigt, geben Sie ihr keinen. React-spezifische Werkzeuge fügen Überhead hinzu. Halten Sie Geschäftslogik-Tests klein, schnell und nahe an der Funktion, die sie überprüfen.
Ein praktischer Split funktioniert gut:
- Hooks: Verwenden Sie
renderHook,act(), und Wrapper-Provider, wenn nötig. - Werkzeuge: Verwenden Sie einfach Jest und keine DOM.
- Zustandsbasierte Schnittstellenlogik: Ziehen Sie es in testbare Hilfsfunktionen, wenn der Komponententest zu viel tut.
Teams füllen Komponententests oft mit Logikannahmen, die tiefer in der Stacks liegen. Wenn Sie diese Logik herausziehen, erhalten Sie zwei Vorteile. Der Komponententest wird sauberer, und der Logiktest wird schneller.
Meisterung fortgeschrittener Techniken: Mocking und Async
Die meisten unzuverlässigen React-Suiten brechen an zwei Stellen. Sie brechen an Grenzen von Abhängigkeiten und sie brechen um Zeit.
Deshalb ist das asynchrone Testen und das Mocking die Trennlinie zwischen einem Spielzeug-Test-Suite und einer, die Sie vor der Veröffentlichung vertrauen können. Eine Analyse gibt an, dass 46,5% der Testflakigkeit auf Umgebungs- oder Ressourcenbezogene Probleme wie asynchrone Timing zurückzuführen ist in dieser React-Einheitstestanalyse. In React-Anwendungen entspricht dies direkt den Zustandsübergängen, der verzögerten Darstellung, der Netzwerkgetriebenen UI und den Tests, die statt deterministischer Wartezeit raten.

Simulieren Sie die Grenze, nicht jede Schicht
Der schnellste Weg, einen irreführenden Test zu schreiben, ist, die Hälfte Ihres Komponentenbaums zu mocken und dann zu behaupten, dass Ihre eigenen Mocks funktioniert haben.
Für eine Komponente, die Kontodaten abruft, mocken Sie den Netzwerkclient oder den API-Modul. Mocken Sie nicht den Hook, das Kind-Row-Component, den Ladeindikator und drei Hilfsfunktionen, es sei denn, der Test benötigt tatsächlich eine Isolation an diesen Schnittstellen.
Verwenden Sie diese Regelsatz:
- Mocken Sie externe Dienste: HTTP-Clients, Analytics, Browser-only-APIs, native Bridges
- Mocken Sie unstabile Plattform-APIs:
matchMediaZeitsteuerungen, Electron-Präloadeingriffe, Capacitor-Plugins, wenn sie in jsdom nicht verfügbar sind - Vermeiden Sie das Mocken Ihrer eigenen Interna standardmäßig: Zusätzliche Hooks, einfache Kinder, lokale Hilfsfunktionen
Wenn ein Test erfolgreich ist, weil alle schwierigen Teile durch Fakes ersetzt wurden, hat es Ihnen nicht viel Vertrauen in die Freigabe gebracht.
Für Teams, die Beispiele und Muster rund um Runner-APIs benötigen, Capgo Testtutorials ein praktischer Referenzspeicher, insbesondere bei der Einarbeitung von Entwicklern, die React kennen, aber noch keine Erfahrung mit Testmechaniken haben.
Asynche Tests scheitern, wenn die Zeitung unbestimmt ist
Asynche Fehlschläge kommen in der Regel von einem von drei Fehlern:
- Der Test behauptet zu früh.
- Der Test wartet mit willkürlichen Zeitschaltungen.
- Das Komponenten-Update erfolgt mehrmals, aber der Test modelliert nur eine Übergang.
Ein stabiler asyncher Test hat normalerweise diese Form:
test('shows user details after data loads', async () => {
render(<UserProfile userId="42" />);
expect(screen.getByText(/loading/i)).toBeInTheDocument();
expect(await screen.findByText(/account owner/i)).toBeInTheDocument();
});
Oder, wenn Sie auf eine bestimmte Bedingung warten müssen:
await waitFor(() => {
expect(screen.getByRole('alert')).toBeInTheDocument();
});
Verwenden Sie findBy wenn die Erscheinung eines Elements das Ereignis ist, auf das Sie Wert legen. Verwenden Sie waitFor wenn die Bedingung breiter ist oder der Zustand nicht mit einer einzelnen Abfrage ausgedrückt werden kann. Vermeiden Sie setTimeout In Tests, es sei denn, Sie testen explizit Timer-Verhalten und verwenden Fake-Timer.
Die Testumgebung von React erwartet auch, dass Sie die Semantik bei Updates respektieren. act() Testing Library handhabt einen großen Teil davon für Sie, aber wenn Sie den Zustand manuell steuern oder Timer vorwärts setzen, müssen Sie immer noch darüber nachdenken, wann Updates abgeschlossen sind.
Wissen, welches Mocking-Tool Sie anwenden sollen.
Verschiedene Mocking-Tools lösen unterschiedliche Probleme:
| Tool | Beste Verwendung | Häufiger Fehler |
|---|---|---|
jest.fn() |
Fiktive Callbacks oder injizierte Funktionen, die einzeln verwendet werden können | Verwendung, um ein ganzes Modul zu ersetzen, wenn ein einfacher Callback ausreicht |
jest.spyOn() |
Eine Methode eines realen Objekts oder Moduls beobachten oder überschreiben | Vergessen, die ursprüngliche Implementierung wiederherzustellen |
jest.mock() |
Ein Modulabhaengigkeit ersetzen an Importgrenze | Große Module durch Mocking standardmäßig und verlieren damit sinnvolle Verhalten |
Beispiele helfen:
- Zurückgreifen
jest.fn()wenn ein Komponente einonSubmitEigenschaft übernimmt. - Verwenden
jest.spyOn()wenn Sie die Verifizierung einer Speichermethode oder eines exportierten __CAPGO_KEEP_0__ Aufrufs benötigen.console.error, a storage method, or one exported API call. - wenn die Importierung eines Moduls sonst an I/O, native __CAPGO_KEEP_0__, oder Verhalten außerhalb der Einheitengrenze stoßen würde.
jest.mock()when importing a module would otherwise hit I/O, native code, or behavior outside the unit boundary.
Examples help: Reach for when a component takes an prop. Use when you need to verify a storage method, or one exported __CAPGO_KEEP_0__ call. Use when importing a module would otherwise hit I/O, native __CAPGO_KEEP_0__, or behavior outside the unit boundary. One advanced area many guides underserve is error-path testing in modern React. Error boundaries, delayed state changes, and async fallback UIs deserve first-class tests, not just the “happy path” click example. If a child throws, assert the fallback UI. If a request fails, assert the visible recovery state. If a button is disabled during loading, assert that too. Those are the bugs users remember.
Improving Test Quality and Strategy
Viele Teams verfolgen immer noch die Abdeckung wie es dasselbe wäre wie Vertrauen. Es ist nicht.
Man kann ein Abdeckungsziel erreichen und trotzdem die Regressionsfehler ignorieren, die wichtig sind. Ein Suite voller oberflächlicher Behauptungen, breiter Szenarios und mockter Interna erzeugt den Eindruck von Sicherheit und erhöht gleichzeitig die Wartungskosten.

Abdeckung ist ein Kartenbild, nicht das Ziel
Abdeckungsberichte sind nützlich, wenn sie eine Frage beantworten: welche kritischen Wege haben noch keine Schutz?
Sie sind nicht nützlich, wenn sie Entwickler dazu bringen, trivialen Wrapper, statische Markup oder eine-Linien-Übertragungsdateien zu testen, nur um einen Prozentsatz zu bewegen. Behandeln Sie Abdeckung als Entdeckungstool. Wenn der Authentifizierungsstatus, die Abrechnungsaktionen, die Feature-Flags oder die Aktualisierungsanfragen keine Tests haben, ist das ein Signal. Wenn ein präsentatives Icon-Komponente keine Tests hat, ist das normalerweise nicht.
Ein gesunder Überprüfungsfrage ist einfach: reduziert diese Test die Auslieferungsrisiken?
- Ja: Es überprüft die Benutzersichtbarkeit auf einem kritischen Weg.
- Vielleicht: Es schützt Geschäftslogik, die leicht während einer Refaktorisierung gebrochen werden kann.
- Nein: Es besagt Implementierungsdetails oder dupliziert den Wert eines anderen Tests.
Was nicht getestet werden sollte
Viele React-Leitfäden geben nicht genug Zeit für die Unterlassung auf. Das Loch ist wichtig, weil übermäßiges Mocken und Implementierungs-Detail-Testen brüchige Suites erzeugen, die zwar bestehen, aber die Benutzererfahrung immer noch bricht, wie in der BrowserStack-Leitfaden zu "was nicht getestet werden sollte in React".
Vermeide oder limitiere diese Muster stark:
- Internes Zustandsprüfungen: Teste nicht
isOpendirekt, wenn du testen kannst, ob das Panel geöffnet wurde. - Framework-Verhalten: Teste nicht, dass React einen Effekt aufgerufen hat. Teste das Ergebnis dessen, was der Effekt ändert.
- Drittanbieter-Bibliothek-Internes: Testen Sie Ihre Integration mit einem Datumsauswahl- oder Routen-Widget, nicht mit der eigenen Renderlogik der Bibliothek.
- Überbrochene Einheiten: Wenn Sie jedes Kind und Hilfsprogramm gemockt haben, testen Sie möglicherweise keine bedeutsamen Verhaltensweisen mehr.
Schlechte Tests sind schlimmer als fehlende Tests, wenn sie Refaktorisierungen blockieren und trotzdem keine Produktionsfehler erkennen.
Eine nützliche Heuristik ist die Eigentümerschaft von Grenzen. Testen Sie, was Ihr code besitzt. Testen Sie nicht, was React, der Browser oder eine reife Bibliothek bereits besitzt, es sei denn, Ihre Integrationsschicht ändert den Vertrag.
Wo helfen Snapshots und wo schaden sie
Snapshots sind nicht nutzlos. Sie werden einfach leicht missbraucht.
Verwenden Sie sie sparsam für Komponenten mit stabilen, einfachen Ausgaben, bei denen eine breite strukturale Differenz bedeutend ist. Vermeiden Sie sie für interaktive oder hochdynamische Komponenten, da sie Lärm erzeugen. Entwickler lesen sie nicht mehr und beginnen, sie reflexiv zu aktualisieren.
Bessere Alternativen gibt es normalerweise:
- Für bedingte Darstellung, behaupten Sie die Präsenz oder Abwesenheit von Schlüsseltext.
- Für visuelle Zustandsänderungen, behaupten Sie die Rolle, Bezeichnung oder Attribut, das zählt.
- Für Fehler und Fallbacks, behaupten Sie den tatsächlichen Fehlermeldung oder Warnbereich.
If Ihr Team ein umfassenderes Qualitätssicherungsverfahren benötigt, das über Einheitstests hinausgeht, ist ein solides Begleiter ein Qualitätsmanagement-Workflow für Apps der Tests, Release-Checks und Rollback-Planung als ein System behandelt. Das ist der Denkansatz, der die Testqualität am schnellsten verbessert. Hört auf, nachzudenken, wie viele Tests Sie haben. Beginnen Sie, nachzudenken, welche Fehler noch auf die Benutzer zukommen könnten.
Integrierte Tests in einem Cross-Plattform-CI/CD-Pipeline
Ein Test-Suite, die nur auf einem Entwickler-Laptop läuft, ist nur eine Empfehlung und kein Kontrollpunkt.
Die Suite wird erst dann operational, wenn jeder Pull-Request die gleichen Checks in einem sauberen Umfeld ausführt und die Merges blockiert, wenn diese Checks fehlschlagen. Das klingt offensichtlich, aber viele Teams lassen immer noch kritische Lücken bestehen. Tests werden manuell durchgeführt. Coverage-Berichte sind optional. Verpackung und Release-Jobs starten, bevor die Test-Jobs abgeschlossen sind. Das ist der Weg, auf dem kleine UI-Regressionen in größere Release-Fehler übergehen.

Ein Pull-Request sollte jedenfalls den gleichen Gate auslösen
Um React mit Einheitstests wie einem Sicherheitsnetz zu simulieren, benötigt CI ein paar Grundlagen:
- Läuft auf jedem Pull-Request
- Installiert Abhängigkeiten aus Lockfile
- Verwendet den gleichen Test-Befehl jedenfalls
- Failen Sie schnell bei Fehlern in den Tests
- Publizieren Sie Artefakte nur, nachdem die Tests erfolgreich waren
Dies ist das Herzstück kontinuierlicher Bereitstellung für App-Teams. Bauen Sie Vertrauen vor der Veröffentlichung, nicht danach.
Eine einfache GitHub Actions-Arbeitsschritt ist für viele Teams ausreichend:
name: test
on:
pull_request:
push:
branches:
- main
jobs:
react-tests:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Set up Node
uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- name: Install dependencies
run: npm ci
- name: Run unit tests
run: npm run test:ci
Dies ist nicht besonders, und das ist der Punkt. Die stärksten Pipelines sind meistens diejenigen, die am wenigsten überraschend sind.
Weshalb dies für Capacitor und Electron wichtiger ist
Cross-platform-React-Apps tragen mehr Risiko bei der Veröffentlichung als Browser-Apps, weil die gleiche UI code oft in verschiedenen Containern mit unterschiedlichen Laufzeitannahmen geliefert wird.
Eine paar Beispiele zeigen, wo Pipelines helfen:
- Capacitor-Apps: Web code mag lokal erfolgreich sein, aber fehlschlagen, wenn ein Plugin-Brücke, Offline-Zustand oder App-Lifecycle-Randfall das Verhalten nach dem Packen ändert.
- Elektron-Anwendungen: Ein Renderer-Komponent kann auf Präloader-APIs, Fenster-Messaging oder Desktop-only-Zustände angewiesen sein, die bei einer reinen Browser-Testung nicht existieren, es sei denn, sie werden absichtlich nachgebildet.
- Gemeinsame Release-Trainings: Ein schlechter Bundle kann auf mehrere Ziele auswirken, wenn Ihr Bereitstellungsprozess die Publikation nicht engmaschig überwacht.
Deshalb sollten Einheitstests vor der Verpackung ausgeführt werden und Verpackungsaufgaben vor der Verteilungsaufgabe. Jeder Schritt verringert das Risiko. Einheitstests fangen lokale Rückschritte schnell ein. Plattform-Verpackung überprüft Umgebungsannahmen. Manuelle Genehmigung oder stufenweise Verteilung handhabt die letzte Vertrauenswürdigkeit.
Ein praktischer GitHub Actions-Workflow
Ein reiferes Pipeline teilt üblicherweise Verantwortlichkeiten:
- Testaufgabe: Schnelle Einheitstests und Hook-Tests
- Bauaufgabe: Produktionsbuild nur nachdem die Tests erfolgreich waren
- Verpackungsaufgabe: Capacitor Synchronisierung, Electron-Paketierung oder Artefaktbündelung
- Ausgabeanforderung: Veröffentlichen Sie nur von genehmigten Branches oder Tags
Für Teams, die live aktualisierte Capacitor- oder Electron-Anwendungen bereitstellen, ist dies der Bereich, in dem die Ausgabeanlagen relevant sind. Eine Option in diesem Workflow ist Capgo, die signierte Web-Bundles für CapacitorJS- und Electron-Anwendungen mit Rollback-Unterstützung und kanalbasierten Ausrollkontrollen veröffentlicht. In der Praxis bedeutet dies, dass Ihr React-Testjob als erste Harte-Sperre fungieren kann, bevor ein Web-Bundle in die Bereitstellung für die Staging- oder Produktionsumgebung kommt.
Die betriebsbezogene Regel ist einfach. Lassen Sie die Ausgabeanlagen nicht die Schwächen der Tests ausgleichen. Verwenden Sie die Ausgabeanlagen nachdem zuverlässige Tests bereits schlechte Änderungen ausgeschlossen haben.
Ein zuverlässiges Testsystem ändert das Verhalten der Teams. Ingenieure fusionieren mit weniger Hesitation. Rezensenten konzentrieren sich auf Randfälle anstatt die Grundlagen manuell nachzurufen. Release-Manager behandeln jeden Deploy nicht mehr wie ein Wettbewerb. Das ist das Ergebnis von gutem Unit-Testing von React.
Wenn Ihr Team React über Capacitor oder Electron bereitstellt, hängt die Sicherheit der Ausgabe von mehr als grünen lokalen Tests ab. Capgo bietet Teams einen kontrollierten Weg, um signierte Web-Updates zu veröffentlichen, Zielkanäle auszuwählen und schlechte Bundles ohne Wartezeit auf die Store-Überprüfung zurückzurufen, was sich natürlich hinter einer CI-Pipeline einfügt, die bereits die Durchführung von Einheitstests vor der Bereitstellung erfordert.