Zum Hauptinhalt springen

Einfache Einheitenprüfung: Eine praktische End-to-End-Anleitung

Meistern Sie die Einheitstests von React von der Einrichtung bis zur CI/CD. Diese Anleitung behandelt Jest, RTL, Hooks, asynche code, Mocking und beste Praktiken für robuste Cross-Plattform-Anwendungen.

Einheitstestung von React: Eine praktische End-to-End-Anleitung

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. Die Pull-Anfrage ist sauber, die Überprüfung ist schnell und die Bereitstellung geht raus.

Eine Stunde später meldet der Support, dass sich das Login auf einer Plattform nicht mehr funktioniert. Web sieht gut aus. Die Desktop-Shell hat einen veralteten Renderweg. Die mobile Anwendung verhält sich anders nach einem asynchronen Zustandswechsel. Niemand hat es bemerkt, weil der code Tests hatte, aber nicht die richtigen Tests und definitiv kein zuverlässiges System um diese Tests.

Dass ist das Hauptproblem bei der Einheitstestung von React in Produktionsteams. Ein paar laufende Tests zu schreiben ist nicht schwer. Ein Suite zu bauen, die dich auch während von Refaktoren, Release-Trainings, Hotfixes und Cross-Plattform-Packaging schützt, ist das schwierige Teil. React-Anwendungen scheitern nicht, weil ein Team vergessen hat, wie man eine Funktion aufruft. render()Sie scheitern, weil Tests sich auf Implementierungsdetails ausrichten, asynche Verhaltensweisen überdeckt werden und CI die Testung wie ein Checkboxt behandelt, anstatt sie als Releasegate.

Moderne Einheitstestung von React funktioniert, wenn sie wie ein Sicherheitssystem funktioniert. Schnelle Feedbacks lokal. Deterministische Überprüfungen in CI. Klares Abgrenzung um was gehört in einen Einheitstest und was nicht. Das ist noch wichtiger, wenn die gleiche React-Anwendung über Browser, Capacitor-Container oder Electron-Shell ausgeliefert wird.

Inhaltsübersicht

Warum Unit-Testing für React Ihr bester Sicherheitsnetz ist

Einheitstests verdienen ihren Platz, wenn sie den Fehler erkennen, den Sie sicher waren, dass er nicht passieren kann. In React bedeutet das normalerweise, dass ein Komponente weiterhin renderet, aber das von einem Benutzer abhängige Verhalten geändert wurde. Ein deaktiver Button wird klickbar. Ein Ladezustand wird nie gelöscht. Eine Fallback-Nachricht verschwindet nach einem Refaktor. Diese Fehler sind klein in code und teuer in der Produktion.

Die React-Testung hat sich in einer wichtigen Weise geändert, als Die React-Testing-Library wurde zum mainstream-Modell für die Testung des Verhaltens anstatt der internen Struktur, was Teams dazu bringt, Tests zu schreiben, die das Benutzer-Verhalten widerspiegeln, anstatt Komponenten-Props oder -Zustände, wie im React Native-Testleitfaden bei React Native-Testübersicht. Dieser Wechsel ist wichtig, weil React code ständig neu angeordnet wird. Hooks werden verschoben. Komponenten werden geteilt. Kontext 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 ein Einheitstest schützen sollte

Ein guter React-Einheitstest schützt einen kleinen Vertrag:

  • Renderte Ausgabe: Sieht der Benutzer das richtige Text, Label, Zustand oder Fallback?
  • Interaktionsverhalten: Klickt, tippt oder schaltet die UI korrekt um?
  • Randverhalten: Verhält sich das Komponente korrekt, wenn es die erwarteten Eingaben, fehlende Daten oder einen Fehlerpfad erhält?

Eine schwache Test schützt das falsche Ding:

  • Komponenteninternes: Zustandsform, private Methoden, nur für die Implementierung bestimmte Props
  • Framework-Mechaniken: Ob React eine Hook intern auf die genaue Weise aktualisiert, wie Sie es erwartet haben
  • Kinderdetails: Markup, das von untergeordneten Komponenten besitzt, die Sie nicht überprüfen möchten

Praktische Regel: Wenn Sie das Komponente ohne Änderung des Benutzererlebnisses oder der Funktionalität umstrukturieren können, sollte der Test auch nicht geändert werden.

Einheiten-Tests sitzen auch in einem umfassenderen Testsystem. Sie sollen nicht beweisen, dass die ganze App funktioniert, von Anfang bis Ende. Sie sind die schnelle Schicht, die Regressionsfehler vor der Notwendigkeit eines Browser-Level-Tests oder einer Geräte-Level-Validierung durchführt. Deshalb sind sie die erste Verteidigungslinie in jedem vernünftigen Stacks von Automatisierte Tests für Produktionsanwendungen.

Für React-Teams, die häufig liefern, kommt die Zuversicht aus dieser Aufteilung der Arbeit. Einheiten-Tests fangen lokale Rückschläge schnell ein. Integrations-Tests überprüfen die Verbindungen. End-to-End-Tests bestätigen die kritischen Wege. Wenn man die Einheitsschicht überspringt, muss alles langsamer unten zu viel Last tragen.

Einrichten Ihres modernen React-Testumfelds

Ein brüchiges Testumfeld schafft flache Tests, bevor Sie eine einzelne Behauptung geschrieben haben. Viele Entwickler beschuldigen Jest, jsdom oder React, wenn das zugrunde liegende Problem eine inkonsistente Konfiguration auf verschiedenen lokalen Maschinen und CI ist. Die Lösung besteht darin, das Umfeld langweilig zu machen. Langweilig ist gut hier.

Eine saubere Arbeitsumgebung mit einem Computermonitor, der React-Einheitstests code in einem code-Editor anzeigt.

Beginnen Sie mit einem vorhersehbaren Runner und Umfeld

Für eine moderne React-Anwendung, insbesondere eine, die mit Vite erstellt wurde, sollte die Grundkonfiguration umfassen:

  • Eine Testrunner: Jest bleibt gängig, insbesondere in älteren React-Codebasen und Unternehmens- CI-Stacks.
  • Eine browserähnliche Umgebung: jsdom lässt Komponententests den DOM-Ausgang rendern.
  • Werkzeuge für die Testbibliothek: @testing-library/react und @testing-library/jest-dom
  • Einstiegspunkt für eine einzelne Konfiguration: Eine Datei, um Matcher und globale Mocks zu registrieren

Die Schlüsselarbeit, die Reacts Testleitfaden unterstützt, ist einfach: Rendern Sie das Komponenten in einer jsdom-gestützten Umgebung, suchen Sie nach der UI mit Selektoren wie getByText oder getByRole, löst die Interaktion aus und bestätigt den DOM-Wechsel, wie beschrieben. React-Testdokumentationbeschrieben. Diese Workflow bleibt nur dann vertrauenswürdig, wenn jede Maschine das gleiche Testumfeld verwendet.

Eine praktische Jest-Konfiguration 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 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 Begleitreferenz für umfassende JavaScript-Testkonventionen benötigen, ist Capgo’s Einheitstests in JavaScript-Leitfaden ein nützliches Teamhandbuch.

Add the setup file your suite will depend on

Ein angemessener 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(),
  })),
});

Diese Datei ist der Ort, an dem Sie Umgebungsunterschiede einmal lösen, anstatt sie in zwanzig Testdateien zu 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 diese werden Entwickler globale Variablen ad hoc anpassen. Das schafft inkonsistente Tests und schwierig zu verfolgende Fehler. Ein lokaler Lauf eines Entwicklers funktioniert, weil er eine manuelle Mock-Datei in einem File hinzugefügt hat. Der CI-Fehler tritt auf, weil die Konfiguration nicht geteilt wurde.

Behalte lokale und CI-Verhalten 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"
  }
}

Eine kurze Anleitung hilft neuen Teammitgliedern, sich schnell an die gleiche Basis zu bringen:

Die wichtigste Einstellung ist Disziplin bei den Standards. Legge Alias in der Konfiguration ab. Legge Umgebungsstubs in einer Einstellungsdatei ab. Verwende jsdom für UI-Tests und eine leichte Umgebung für reine Utilities, wenn möglich. Je weniger individuelles Verhalten jede einzelne Testdatei benötigt, desto zuverlässiger wird Ihr System.

Einzelne Komponenten testen

Organisationen haben kein Problem, Tests zu schreiben. Sie haben ein Problem, Tests zu schreiben, die nach sechs Monaten noch Bedeutung haben.

Der Standardmuster für die Einheitstests von React-Komponenten ist immer noch das richtige: Die Komponente rendern, die Benutzeroberfläche mit benutzerzentrierten Selektoren abfragen, eine Interaktion auslösen und die resultierende DOM-Änderung überprüfen, was Tests von Implementierungsdetails wie Zustand oder Props fernhält, wie in der React-TestanleitungDie Herausforderung liegt darin, dieses Muster mit Beschränkung anzuwenden.

Testen Sie das Akkordeon wie ein Benutzer es verwendet

Nehmen Sie eine grundlegende Accordion Komponente. Sie rendernt einen Button mit einem Titel. Der Inhalt des Panels beginnt versteckt. Durch Anklicken des Buttons wird der Inhalt sichtbar gemacht und der Barrierefreiheitsszustand aktualisiert.

Das reicht für mehrere nützliche Tests.

  1. Das ist genug Verhalten für mehrere nützliche Tests:
  2. Klicken Sie auf den Trigger, um den Inhalt zu enthüllen.
  3. Klicken Sie erneut, um ihn zusammenzufalten.
  4. Zugänglichkeitsattribute spiegeln den sichtbaren Zustand wider.

Dieser letzte Punkt wird oft übersehen. Wenn Ihr Komponente aria-expanded, aria-controls oder eine rolengestützte Struktur verwendet, überprüfen Sie sie. Das sind keine Implementierungsdetails. Sie sind Teil des Benutzerinterface-Kontrakts.

Die besten Komponententests sehen aus wie ein Fehlerbericht, den Sie nie erhalten möchten.

Wählen Sie Abfragen basierend auf der Absicht

React Testing Library bietet Ihnen mehrere Abfragemuster, aber sie sind nicht austauschbar. Die falsche Wahl macht Tests laut oder irreführend.

Abfrageart Wenn das Element gefunden wird Wenn das Element nicht gefunden wird Beispiel für die Verwendung
getBy Gibt das Element sofort zurück Würfelt sofort einen Fehler Behauptet, dass ein Button oder ein Titel bereits auf dem Bildschirm sein sollte
queryBy Gibt das Element sofort zurück Gibt zurück null Behauptet, dass versteckte Inhalte vor der Interaktion nicht existieren sollten
findBy Beendet sich, wenn das Element erscheint Abgelehnt wird, nachdem gewartet wurde Der asynchrone geladene Inhalt erscheint nach einem Fetch oder einem verzögerten Update.

Eine einfache mentale Vorstellung hilft:

  • Verwende getBy für Dinge, die bereits existieren müssen.
  • Werden queryBy für Dinge, die noch nicht existieren dürfen.
  • Werden findBy wenn sich die Benutzeroberfläche später ändert.

weil sich die Benutzeroberfläche später ändert. findBy für alles bedeutet es normalerweise, dass der Autor nicht weiß, wann das Komponenten aktualisiert wird. Diese Unsicherheit wird später zu Unzuverlässigkeit.

Ein praktisches Akkordeon-Beispiel

Ein praktisches Beispiel für einen Akkordeon-Test:

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>
  );
}

Hier ist ein repräsentatives Komponenten-Beispiel:

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, setOpen Was fehlt, ist genauso wichtig. Es gibt keine Behauptung gegen den internen Zustand. Keine Überprüfung, ob

Einige Gewohnheiten machen Komponententests stärker:

  • Benutze role-basierte Abfragen: Knöpfe, Überschriften, Dialoge, Warnungen und Eingabefelder sollten normalerweise über ihre Rolle gefunden werden.
  • Jeder Test sollte eng gefasst sein: Ein Verhalten pro Test hilft bei lesbarer Fehlermeldung.
  • Benenne Tests nach ihren Ergebnissen: “aktualisiert aria-expanded, wenn geöffnet” ist viel nützlicher als “funktioniert richtig.”

Wenn ein Komponente schwer zu testen ist, liegt das oft an einem Designproblem. Vielleicht versteckt sie den Zustand an falschem Ort. Vielleicht fehlt ihr semantischer Markup. Gute Tests drängen Teams oft zu besseren Komponenten.

Testen von benutzerdefinierten Hooks und Anwendungslogik

React-Anwendungen verstecken viel wichtige Funktionalität außerhalb von Komponenten. Zustandsübergänge leben in Hooks. Validierung und Formatierung leben in Hilfsfunktionen. Die Datenformierung findet oft vor dem Rendern statt. Wenn Sie nur sichtbare Komponenten testen, werden Sie ein großes Stück der code übersehen, das den Produktionsverhalten noch brechen kann.

Hooks benötigen eine React-fähige Umgebung

Ein benutzerdefinierter Hook benötigt immer noch React, um korrekt auszuführen, also testiere ihn mit renderHook und umschließen Sie Aufrufe, die den Zustand ändern act().

A kleine useToggle Ein 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 };
}

Ihr 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);
});

Das Test ist nützlich, weil der Hook selbst die Einheit ist. Sie testen nicht die React-Internen. Sie überprüfen das externe Verhalten des Hooks.

For product teams building reusable UI or feature primitives, this pattern matters a lot. Hooks often become the interface shared across apps, design systems, or internal tooling. If you’re designing reusable behavior with commercial intent, resources on Funktionen für Herstellerprodukte Kann dabei helfen, Hooks als standardisierte Bausteine anzubieten, anstatt sie nur als Implementierungsdetails zu betrachten.

Reine Logik sollte in Tests rein bleiben

Nicht alles muss getestet werden jsdom, React oder Testing Library. Wenn eine Funktion rein ist, testen Sie sie mit reinem Jest in einem Node-Umgebung.

Example:

export function formatDisplayName(firstName: string, lastName: string) {
  return `${firstName.trim()} ${lastName.trim()}`.trim();
}

Das Test sollte 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');
});

Die Gewinne hier sind Geschwindigkeit und Klarheit. Wenn eine Funktion keinen renderierten Baum benötigt, vergeben Sie ihr keinen. Die React-spezifische Werkzeugkiste fügt Überhead hinzu. Halten Sie die Tests für Geschäftslogik klein, schnell und nahe bei der Funktion, die sie überprüfen soll.

Eine praktische Aufteilung funktioniert gut:

  • Hooks: Use renderHook, act(), und Wrapper-Provider, wenn erforderlich.
  • Werkzeuge: Verwenden Sie plain Jest und keine DOM.
  • Zustandsbehaftete Schnittstellenlogik: Ziehen Sie sie in testbare Hilfsfunktionen, wenn der Komponententest zu viel tut.

Teams überfüllen oft Komponententests 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 die Zeit herum.

Das ist der Grund, warum asynchrone Tests und Mocks die Grenze zwischen einem Spielzeug-Test-Suite und einer, die Sie vor der Veröffentlichung vertrauen können, darstellen. Eine Analyse zufolge 46,5% der Testunzuverlässigkeit werden auf Umgebungs- oder Ressourcenbezogene Probleme wie asynchrone Timing in dieser Analyse zu Reaktor-Unit-Tests. In Reaktor-Anwendungen entspricht dies direkt den Zustandsübergängen, der verzögerten Darstellung, der Netzwerk-gesteuerten Benutzeroberfläche und Tests, die statt deterministischer Wartezeit raten.

Eine Vergleichstabelle, die Advanced React Testing Techniques, insbesondere Mocking Dependencies gegenüber Asynchronen Tests, zeigt.

Mocke die Grenze, nicht jede Schicht

Die schnellste Möglichkeit, 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 ein Komponent, das Konten-Daten abruft, mocken Sie den Netzwerk-Client oder API-Modul. Mocken Sie nicht den Hook, das Kind-Row-Komponent, den Lade-Spinner und drei Hilfsfunktionen, es sei denn, der Test benötigt tatsächlich Isolation an diesen Schnittstellen.

Verwenden Sie diese Regelsatz:

  • Mocken Sie externe Dienste: HTTP-Clients, Analytics, Browser-only-APIs, native Bridges
  • Mock unstabile Plattform-APIs: matchMedia, Timern, Electron-Vorladefunktionen, Capacitor-Plugins, wenn diese in jsdom nicht verfügbar sind
  • Vermeide das Mocken eigener Interna standardmäßig: Benutzerdefinierte Hooks, einfache Kinder, lokale Hilfsfunktionen

Wenn ein Test erfolgreich ist, weil alle schwierigen Teile durch Fakes ersetzt wurden, hat er Ihnen nicht viel Vertrauen in die Releasefähigkeit gebracht.

Für Teams, die Beispiele und Muster rund um Runner-APIs benötigen, Capgo Testtutorials ist eine praktische Referenzbibliothek, insbesondere, wenn Entwickler, die React kennen, aber noch nicht die Testmechanik kennen, aufgenommen werden.

Asynchrone Tests scheitern, wenn die Zeitung vage ist

Asynchrone Fehler kommen normalerweise aus einem der drei Fehler:

  1. Der Test behauptet zu früh.
  2. Der Test wartet mit willkürlichen Timern.
  3. Der Komponenten wird mehr als einmal aktualisiert, aber der Test modelliert nur eine Übergang.

Ein stabiler asynchrone 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();
});

Use findBy wenn die Erscheinung eines Elements der Ereignis ist, auf das Sie achten. 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 Timerverhalten und verwenden fiktive Timer.

React's Testumgebung erwartet auch, dass Sie Respekt zeigen act() semantics around updates. Testing Library handles a lot of this for you, but if you’re driving state manually or advancing timers, you still need to think about when updates flush.

Wissen, welches Mocking-Tool zu greifen ist

Verschiedene Mocking-Tools lösen unterschiedliche Probleme:

Tool Beste Verwendung Häufiger Fehler
jest.fn() Stehende Fake-Aufrufe oder injizierte Funktionen Verwendung zur Ersetzung eines ganzen Moduls, wenn ein einfacher Aufruf ausreicht
jest.spyOn() Beobachten oder überschreiben Sie eine Methode auf einem realen Objekt oder Modul Vergessen Sie, die ursprüngliche Implementierung wiederherzustellen
jest.mock() Ersetzen Sie eine Modul-Abhängigkeit an der Import-Grenze Vordefinierte Mocking von großen Modulen und Verlust von bedeutender Funktionalität

Beispiele helfen:

  • Greifen Sie nach jest.fn() wenn ein Komponente einen onSubmit prop.
  • Use jest.spyOn() wenn Sie die Funktionalität überprüfen müssen console.error, eine Speichermethode oder eine exportierte API-Aufruf.
  • Use jest.mock() wenn beim Import eines Moduls andernfalls auf I/O, native code, oder Verhalten außerhalb der Einheitsgrenze stoßen würde.

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.

Qualität der Tests verbessern und Strategie

Viele Teams verfolgen immer noch die Abdeckung wie es dasselbe wäre wie Vertrauen. Es ist nicht.

You can hit a coverage target and still miss the regressions that matter. A suite full of shallow assertions, broad snapshots, and mocked internals creates the appearance of safety while also increasing maintenance cost.

Ein Infografik, die die Vorteile der Qualitätstests gegenüber dem Aufwand der Wartung von großen Test-Suiten vergleicht.

Abdeckung ist ein Wegweiser, nicht das Ziel

Deckungsbeitragsberichte sind nützlich, wenn sie eine Frage beantworten: welche kritischen Pfade haben noch keine Absicherung?

Sie sind nicht nützlich, wenn sie Entwickler dazu drängen, trivialle Wrapper, statische Markup oder einezeilige Durchgänge zu testen, nur um einen Prozentsatz zu verbessern. Behandeln Sie die Abdeckung als Entdeckungstool. Wenn der Authentifizierungsstatus, die Abrechnungsaktionen, die Featureflags oder die Aktualisierungsanfragen keine Tests haben, ist das ein Signal. Wenn ein präsentatives Icon-Komponenten keine Tests hat, ist das normalerweise nicht der Fall.

Ein gesunder Überprüfungsfrage ist einfach: reduziert diese Test die Freigabefrisik?

  • Ja: Es überprüft die Benutzersichtbarkeit auf einer kritischen Pfad.
  • Vielleicht: Es schützt Geschäftslogik, die leicht während einer Refaktorisierung beschädigt werden kann.
  • Nein: Es behauptet Implementierungsdetails oder dupliziert den Wert eines anderen Tests.

Was nicht getestet werden sollte

Viele React-Leitfäden geben noch nicht genug Zeit für die Omission. Diese Lücke ist wichtig, weil das Über-mocken und das Implementierungsdetail-Testen brüchige Suites erzeugen, die zwar durchgehen, aber die Benutzererfahrung immer noch brechen, wie in der BrowserStack-Leitfaden auf Vermeiden oder stark einschränken Sie diese Muster:.

Vermeiden oder stark einschränken Sie diese Muster:

  • Internes Zustandsprüfungen: Testen Sie nicht isOpen direkt, wenn Sie prüfen können, ob das Panel geöffnet wurde.
  • Framework-Verhalten: Testen Sie nicht, dass React einen Effekt aufgerufen hat. Testen Sie das Ergebnis dessen, was der Effekt ändert.
  • Drittanbieter-Bibliothek-Internes: Testen Sie Ihre Integration mit einem Datumsauswahl- oder Routen-Tool, nicht die eigene Render-Logik der Bibliothek.
  • Über-brochene Einheiten: Wenn Sie jedes Kind und Hilfsprogramm gemockt haben, testen Sie möglicherweise nicht mehr bedeutungsvolle Verhaltensweisen.

Schlechte Tests sind schlimmer als fehlende Tests, wenn sie Refaktorisierungen blockieren und trotzdem nicht in der Lage sind, Produktionsfehler zu erkennen.

Eine nützliche Heuristik ist die Eigentumsübernahme an 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 Snapshots helfen und wo sie schaden

Snapshots sind nicht nutzlos. Sie werden nur leicht missbraucht.

Verwenden Sie sie sparsam für Komponenten mit stabilen, einfachen Ausgaben, bei denen eine breite strukturelle 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 reflexartig zu aktualisieren.

Bessere Alternativen existieren normalerweise:

  • Für bedingte Anzeige, behaupten Sie die Präsenz oder Abwesenheit von Schlüsseltext.
  • Für visuelle Zustandsänderungen, behaupten Sie die Rolle, Bezeichnung oder Eigenschaft, die zählt.
  • Für Fehler und Fallbacks, behaupten Sie den tatsächlichen Hinweis oder Warnbereich.

Wenn Ihr Team ein umfassenderes Qualitätssicherungsprozess außerhalb von Einheitstests benötigt, ist ein solides Begleiter ein Qualitätsmanagement-Workflow für Anwendungen der Tests, Release-Überprüfungen und Rollback-Planung als ein System behandelt. Das ist der geistige Schub, der die Testqualität am schnellsten verbessert. Stellen Sie nicht mehr die Frage, wie viele Tests Sie haben. Beginnen Sie, die Frage zu stellen, welche Fehlfälle noch erreichen können.

Integrierte Tests in einer Cross-Plattform-CI/CD-Pipeline

Eine Testsuite, die nur auf einem Entwickler-Notebook läuft, ist eine Empfehlung, nicht ein Kontrollpunkt.

Die Suite wird operativ, wenn jede Pull-Anfrage die gleichen Überprüfungen in einem sauberen Umfeld durchführt und die Merges blockiert, wenn diese Überprüfungen fehlschlagen. Das klingt offensichtlich, aber viele Teams lassen immer noch kritische Lücken bestehen. Tests werden manuell durchgeführt. Abdeckungsberichte sind optional. Verpackungs- und Release-Jobs beginnen, bevor die Test-Jobs abgeschlossen sind. Das ist, wie kleine UI-Regressionen in größere Release-Fehler schlüpfen.

A fünf-Schritt-Flowchart, das den Prozess der Integration von React-Automationsprüfungen in einen CI/CD-Entwicklungs-Pipeline illustriert.

Ein Pull-Request sollte jeden Gate auslösen, egal wie oft.

Für die Einheitstestung von React wie eine Sicherheitsnetz zu agieren, benötigt CI einige Grundvoraussetzungen:

  • Jeder Pull-Request ausführen
  • Abhängigkeiten aus Lockfile installieren
  • Jedes Mal denselben Testbefehl verwenden
  • Bei Testfehlern schnell fehlschlagen
  • Ergebnisse nur nach erfolgreichem Test veröffentlichen

Dies ist der Kern der kontinuierlichen Bereitstellungspraktiken für App-Teams. Vertrauen aufbauen, bevor man loslässt, nicht danach.

Ein einfacher GitHub Actions-Workflow reicht für viele Teams aus:

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

Das ist nicht besonders, und das ist der Punkt. Die stärksten Pipelines sind meistens die überraschendsten.

Warum das für Capacitor und Electron wichtiger ist

Cross-platform-Apps mit React haben mehr Risiko bei der Veröffentlichung als Browser-Apps, weil die gleiche UI code oft in verschiedenen Containern mit unterschiedlichen Laufzeitannahmen geliefert wird.

Einige Beispiele zeigen, wo Pipelines helfen:

  • Capacitor-Apps: Eine Web code kann lokal funktionieren, aber fehlschlagen, wenn ein Plugin-Brücke, Offline-Zustand oder App-Lifecycle-Edge-Case das Verhalten nach der Verpackung ändert.
  • Elektron-Apps: Ein Renderer-Komponent kann auf Präloader-APIs, Fenster-Messaging oder Desktop- nur-Zustand angewiesen sein, der in einer reinen Browser-Testung nicht existiert, es sei denn, er wird absichtlich nachgemacht.
  • Gemeinsame Veröffentlichungs-Train: Ein schlechter Bundle kann mehrere Ziele beeinflussen, wenn Ihr Verteilungsprozess nicht eng an die Publikation grenzt.

Deswegen sollten Einheitstests vor Verpackungsaufgaben laufen und Verpackungsaufgaben vor Verteilungsaufgaben. Jeder Schritt reduziert das Risiko. Einheitstests fangen lokale Rückschritte schnell ein. Plattform-Verpackungen überprüfen Umgebungsannahmen. Manuelle Genehmigung oder stufenweise Veröffentlichung handhabt die letzte Veröffentlichungsvertraulichkeit.

Ein praktischer GitHub Actions-Workflow

Aufreifere Pipelines teilen üblicherweise Verantwortlichkeiten auf:

  1. Testaufgabe: Rapide Einheitstests und Hooks
  2. Bauaufgabe: Produktionsbau nur nachdem Tests erfolgreich sind
  3. Paketaufgabe: Capacitor Synchronisierung, Electron-Paketierung oder Artefaktbündelung
  4. Freigabeaufgabe: Veröffentlichen nur aus genehmigten Branches oder Tags

Für Teams, die live Updates an Capacitor oder Electron-Anwendungen liefern, ist hier die Release-Tooling entscheidend. Eine Option in diesem Workflow ist CapgoContext: HTML-Textfragment aus einer längeren Capgo-UI-Zeichenfolge (Elternschlüssel `submitting_a_pr_to_capgo`). Seite/Bereich: Capgo-Marketing-Website. Rolle: Website-Kopfzeile. Gesehen in: Seite contributing.astro. Bewahrt Capgo-Produkt/Markenname und Entwicklertrems genau. Nachrichtenschlüssel `submitting_a_pr_to_capgo` (Ein Pr Abgeben an Capgo).

Die Betriebsregel ist einfach. Lassen Sie die Veröffentlichungsinfrastruktur nicht für schwache Tests ausgleichen. Verwenden Sie die Veröffentlichungsinfrastruktur erst nachdem zuverlässige Tests bereits schlechte Änderungen ausgesiebt 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 neu zu laufen. Release-Manager behandeln jeden Deploy nicht mehr wie ein Wettbewerb. Das ist das Ergebnis eines guten Unit-Testings von React.


Wenn Ihr Team React über Capacitor oder Electron verteilt, hängt die Veröffentlichungssicherheit von mehr als grünen lokalen Tests ab. Capgo gibt Teams eine kontrollierte Möglichkeit, signierte Web-Updates zu veröffentlichen, Zielgruppen zu definieren und schlechte Pakete ohne Wartezeit auf die Store-Überprüfung zurückzudrehen, was sich natürlich hinter einer CI-Pipeline einfügt, die bereits die Einhaltung von Unit-Tests vor der Veröffentlichung erfordert.

Live Updates für Capacitor-Apps

Wenn ein Fehler im Web-Layer lebt, schicken Sie die Reparatur über Capgo anstatt Tage zu warten, bis die App-Store-Zulassung genehmigt ist. Die Benutzer erhalten die Aktualisierung im Hintergrund, während native Änderungen im normalen Review-Prozess bleiben.

Menschliche Unterstützung von Martin

Get Started Now

Neueste von unserem Blog

Capgo bietet Ihnen die besten Einblicke, die Sie benötigen, um eine wirklich professionelle mobile App zu erstellen.