Sie befinden sich wahrscheinlich in einer von zwei Situationen. Entweder Ihr JavaScript-Projekt hat fast keine Tests und jede Refaktorisierung fühlt sich riskant an, oder Sie haben bereits Tests und die Hälfte davon ist langsam, brüchig und schwer zu vertrauen.
Das wird sich in Capacitor und Electron Anwendungen noch verschlimmern. Ein einfacher Feature kann auf gemeinsame Geschäftslogik, Browser-APIs, native Plugins, lokale Dateien, IPC und Remote-Dienste in derselben Fluss aufrufen. Wenn Sie diese Teile falsch testen, wird Ihr Test-Suite zu einem Labyrinth an fiktiven Abhängigkeiten. Wenn Sie sie richtig testen, erhalten Sie schnelles Feedback auf die Logik, die bricht.
Gute Einheitstests für JavaScript funktionieren nicht mit cleverer Matcher-Syntax. Sie beginnen mit einer disziplinierten Grenze: Testen Sie reine Logik direkt, isolieren Sie Nebeneffekte und vermeiden Sie es, Tests zu schreiben, die zusammenbrechen, wenn Sie einen internen Funktion umbenennen.
Inhaltsverzeichnis
- Wählen Sie Ihren JavaScript-Testframework
- Projektsetup und Ihre erste Einheitstest
- Meisterung von Mocks und asynchronen Code
- Fortgeschrittene Strategien für robuste Tests
- Testen für CI, Capacitor, und Electron Apps
- Häufig gestellte Fragen zum JavaScript-Einheitstesten
Wählen Sie Ihren JavaScript-Testframework
Ein professionelles JavaScript-Projekt benötigt einen echten Testrunner. Ad-hoc-Skripte und manuelle Konsolenprüfungen schalen nicht, wenn mehrere Ingenieure an demselben Codebase arbeiten. Sie benötigen Testentdeckung, Assertions, asynche Handhabung, Mocks und eine Möglichkeit, alles konsistent in der lokalen Entwicklung und CI auszuführen.
Aktuelle Leitlinien konvergieren auf eine kleine Anzahl von Mainstream-Optionen. Jest, Mocha und Jasmine werden wiederholt als primäre Frameworks hervorgehoben, mit Jest oftmals für die integrierte Teststruktur, Assertions, Mocking und asynche Unterstützung in einem Paket hervorgehoben, wie in diesem Pluralsight-Lab für JavaScript-Tests Ein Vergleichsdiagramm, das beliebte JavaScript-Testframeworks einschließlich Jest, Mocha, Cypress und Playwright zeigt..

Das erste Missverständnis, das Teams haben, ist, dass Einheitstests eine Nebentätigkeit sind. Das führt normalerweise zu inkonsistenten Dateinamen, eigenen Assertions, die niemand mehr kennt, und Helfern, die nur einer Person bekannt sind.
Ein Framework gibt dir eine gemeinsame Sprache:
Teststruktur
- mit __CAPGO_KEEP_0__
describeundtestoderit - Ansprüche mit lesbaren Vergleichern
- Hooks für die Einrichtung und den Abbau
- Asynchroner Support für Versprechen und Timer
- Tools zum Nachahmen für externe Abhängigkeiten
Wenn Ihr Team auch einen umfassenderen Überblick über die Automatisierung von Tests benötigt, als nur auf der Ebene der Einheiten arbeiten, hat Capgo eine nützliche Übersicht über automatisierte Tests in App-Lieferungsworkflows.
Jest vs Mocha im Überblick
Jest und Mocha vertreten zwei unterschiedliche Philosophien.
Jest ist die alles-in-einem-Option. Sie liefert den meisten Teams am ersten Tag alles, was sie benötigen.
Mocha ist modularer. Sie liefert einen Runner und erwartet, dass Sie den Rest der Stacks selbst zusammenstellen.
| Funktion | Jest | Mocha |
|---|---|---|
| Setup-Komplexität | Geringer für die meisten Teams | Höher, da Sie normalerweise Assertion- und Mocking-Bibliotheken hinzufügen müssen |
| Ansprüche | In der Standardausstattung | Normalerweise mit einer anderen Bibliothek kombiniert |
| Mocken | In der Standardausstattung | Normalerweise mit einer anderen Bibliothek kombiniert |
| Asynchrones Testen | In der Standardausstattung und direkt | Unterstützt, aber hängt mehr von der Umgebung ab |
| Abdeckungsworkflow | Häufig in die gleiche Werkzeugkette integriert | Oft mehr zusammengefügt |
| Best fit | Neue Projekte, Teams, die konsistente Ergebnisse wollen | Legacy-Stacks, Teams, die modularen Kontrol haben wollen |
Praktische Regel: Wenn Ihr Team fragen muss, welche Assertion-Bibliothek und Mocking-Bibliothek mit dem Runner kombiniert werden sollen, wollen Sie wahrscheinlich Jest.
Was ich für die meisten Teams empfehle
Für die meisten modernen Projekte würde ich Jest es sei denn, das Codebase hat starke Gründe, sich auf Mocha zu konzentrieren. Diese Empfehlung wird stärker, wenn die Anwendung Capacitor oder Electronweil diese Projekte bereits genug Komplexität haben. Die Reduzierung von Testwerkzeugen bringt sich schnell zurück.
Mocha macht noch Sinn in älteren Node.js-Diensten oder langlebigen Codebases, wo das umliegende Ökosystem bereits abgeschlossen ist. Aber für einen mittelständischen Ingenieur, der von vorne eine robuste Suite aufbaut, entfernt Jest in der Regel mehr Hindernisse als es schafft.
Eine wichtige Anmerkung zum Umfang. Cypress und Playwright sind hervorragende Werkzeuge, aber sie lösen ein anderes Problem. Sie sind besser für Browser-Ebene- und End-to-End-Überprüfungen geeignet, nicht für die schnelle innere Schleife, in der Einheitstests JavaScript-Code leben sollten.
Projektsetup und Ihre erste Test
Ein sauberes Testsetup sollte langweilig sein. Wenn die Hinzufügung der ersten Test kompliziert erscheint, wird die Suite wahrscheinlich nicht gesund bleiben.

Einfache Jest-Einrichtung
Beginnen Sie mit einem JavaScript-Projekt, das bereits eine package.jsonDann fügen Sie Jest als Entwicklungsabhängigkeit hinzu und verbinden Sie eine Testskript.
{
"scripts": {
"test": "jest"
}
}
Das reicht für viele Projekte aus. Sie können später mehr Konfiguration hinzufügen, wenn Ihr Modulsystem, die Transpilation oder die Struktur Ihres Monorepos es erfordert.
Wenn Sie ein Capacitor-Anwendungsprojekt lokal erstellen und Ihr Entwicklungs-Umgebung vor der Hinzufügung von Tests um die gemeinsame Logik in Ordnung haben möchten, folgen Sie Capgo's Anleitung zum einstellen einer Capacitor-Lokalumgebung ist ein praktischer Begleiter.
Schreiben Sie den Test vor der code
Das Test-Vorher-Pattern ist nicht nur eine persönliche Vorliebe. Die US-amerikanische Bundesbehörde für den Verbraucherschutz empfiehlt in ihrer JavaScript-Richtlinie ausdrücklich den Test zuerst zu schreiben, Tests zu organisieren mit describe und it, und Prüfungen um expect(...) Ansprüche herum zu bilden in ihrer JavaScript-Einheitstest-Richtlinie.
Das zählt, weil Test-Vorher die Art und Weise ändert, wie Sie code entwerfen. Funktionen tendieren dazu, kleiner zu werden, Abhängigkeiten werden sichtbarer und Nebeneffekte stoppen, in die Logik zu sickern, die rein bleiben soll.
Hier ist ein minimaler Beispiel:
// math.js
function addTax(amount, rate) {
return amount + amount * rate;
}
module.exports = { addTax };
// math.test.js
const { addTax } = require('./math');
describe('addTax', () => {
it('returns the amount with the tax applied', () => {
expect(addTax(100, 0.2)).toBe(120);
});
});
Verwenden Sie Arrange Act Assert jede Zeit
The Arrange, Act, Assert Die
- Muster hilft dabei, dass Tests lesbar bleiben, selbst wenn sie komplexer werden. Arrange
- die Eingaben und die notwendige Vorbereitung. Act
- durch Aufruf der Funktion. Assert
auf das Ergebnis.
function isSupportedPlatform(platform) {
return ['ios', 'android', 'web', 'desktop'].includes(platform);
}
describe('isSupportedPlatform', () => {
it('returns true for ios', () => {
// Arrange
const platform = 'ios';
// Act
const result = isSupportedPlatform(platform);
// Assert
expect(result).toBe(true);
});
});
Angewendet auf einen Validierungs-Helfer:
Kleine Tests halten sich gut. Ein Test sollte normalerweise eine Frage beantworten, nicht eine gesamte Ablaufbeschreibung erzählen. Für Capacitor- und Electron-Projekte ist diese Disziplin noch wichtiger, weil Ihre logische Rechenoperation oft neben native oder Desktop-Integrationen code liegt. Halten Sie die Geschäftsregel ohne die Plattform- Runtime testbar, und Ihr erster Test wird nicht der letzte nützliche sein.
Mastering Mocks und asynchrone Code
Die meisten Fehler in der Anwendungs code kommen nicht von der Addition zweier Zahlen. Sie kommen von code die sich außerhalb selbst befindet: Netzwerk-Anfragen, Dateien, Plugin-APIs, Timer, IPC-Kanäle, Speicherschichten.
Dort hilft das Mocken. Es gibt dir die Kontrolle über die Grenze, damit der Test sich auf die Entscheidungsfindung deiner code konzentrieren kann.

Mocke Grenzen, nicht alles
Leitfaden für wartbare Tests betont eine einzelne Verhaltensabdeckung und eine starke Behauptung pro Test, und es warnt auch davor, Mocks übermäßig zu verwenden, was Tests brüchig und eng an Implementierungsdetails gekoppelt macht, wie in diesem Artikel von TestRail zu wartbaren Einheitstests.
Dieses Warnsignal ist in JavaScript sehr wichtig. Teams beginnen oft damit, jeden importierten Modul zu mocken und enden damit, ob Funktionen andere Funktionen in der richtigen Reihenfolge aufrufen, anstatt das echte Verhalten zu testen.
Falsches Ziel für einen mock-reichen Test:
- ob Hilfsfunktion A die Hilfsfunktion B aufgerufen hat
- ob Dienst C die Serializer D aufgerufen hat
- ob eine interne private Funktion zweimal aufgerufen wurde
Besseres Ziel:
- was die Funktion zurückgegeben hat
- ob sie eine fehlgeschlagene Abhängigkeit richtig behandelt hat
- ob sie die Daten in die erwartete Form umgewandelt hat
Ein besseres Muster für Capacitor und Electron code
Bei mobilen und Desktop-Anwendungen bevorzuge ich eine Wrapper-Schicht um native oder Plattform-APIs herum. Dann werden die Einheitstests die Wrapper, nicht die Plattform selbst, mocken.
Beispielstruktur:
// cameraGateway.js
async function getPhoto(cameraPlugin) {
return cameraPlugin.getPhoto();
}
module.exports = { getPhoto };
// profilePhotoService.js
async function loadProfilePhoto(cameraGateway) {
const photo = await cameraGateway.getPhoto();
return { path: photo.path, ready: true };
}
module.exports = { loadProfilePhoto };
// profilePhotoService.test.js
const { loadProfilePhoto } = require('./profilePhotoService');
test('returns mapped photo data', async () => {
const fakeCameraGateway = {
getPhoto: jest.fn().mockResolvedValue({ path: '/tmp/pic.jpg' })
};
const result = await loadProfilePhoto(fakeCameraGateway);
expect(result).toEqual({ path: '/tmp/pic.jpg', ready: true });
});
Das Muster funktioniert auch für Electron. Wrap ipcRendererDateien, Zugriffe oder Shell-Integrationen hinter einer dünnen Adapter-Schicht. Einheitenstests treffen die Dienstschicht, nicht die Laufzeit direkt.
Für Teams, die die Release-Logik und die Update-Pfade in Capacitor-Anwendungen testen, hat Capgo eine relevante Anleitung zu dem Testen von Capacitor OTA-Updates mit Mock-Szenarien.
Eine schnelle Übersicht hilft, wenn Ihr Team noch die asynchrone Test-Style normalisiert:
Testen asynchrone Flüsse ohne Flakiness
Verwenden Sie async/await in Tests, wenn der code unter Test eine Promise zurückgibt. Es ist klarer als die callback-reiche Muster und einfacher zu debuggen.
async function fetchProfile(api) {
const response = await api.getUser();
return response.name;
}
test('returns the user name from the API response', async () => {
const api = {
getUser: jest.fn().mockResolvedValue({ name: 'Ava' })
};
const result = await fetchProfile(api);
expect(result).toBe('Ava');
});
Auch den Fehlerpfad testen:
test('throws when the API request fails', async () => {
const api = {
getUser: jest.fn().mockRejectedValue(new Error('network failed'))
};
await expect(fetchProfile(api)).rejects.toThrow('network failed');
});
Testen Sie sowohl den glücklichen Weg als auch den hässlichen Weg. In der Produktion ist der hässliche Weg meist der, den die Benutzer merken.
Fortgeschrittene Strategien für Robuste Tests
Eine Test-Suite wird nützlich, wenn sie nach dem code-Wechsel noch nützlich ist. Das ist schwieriger als die Schreibaufgabe von einer Menge von Tests, die laufen.

Verwenden Sie die Testspaltung als Budget
Ein praxisorientierter Leitfaden empfiehlt eine 70/20/10 aufgeteilt über Einheiten-, Integrations- und End-to-End-Tests, wobei Einheitstests die schnellste Rückmeldung und die stabilsten Fehler liefern. Die gleiche Anleitung sagt, dass ein vollständiger Einheitstest idealerweise in unter 10 Sekunden, und die Prüfungen vor dem Commit sollten bleiben unter 5 Sekunden, laut diesem OpenReplay-Testleitfaden.
Ich betrachte das als Budgetierungstool, nicht als Religion. Wenn sich die meisten Ihrer Anstrengungen auf End-to-End-Tests konzentrieren, werden Ihre Teammitglieder zu lange auf Rückmeldung warten. Wenn alles nur Einheitstests sind, werden Sie die realen Systemgrenzen verpassen.
Für eine Capacitor- oder Electron-Anwendung sieht ein gesunder Ausgleich normalerweise so aus:
- Einheitstests Für die Preisanrechnung, Berechtigungsregeln, Serialisierung, Aktualisierungsbedingungen, Feature-Flags und Zustandsübertragungen
- IntegrationsTests Für Speicherverbindungen, Plugin-Wrapper und IPC-Verträge
- E2E-Tests Für einige kritische Reiserouten wie Anmeldung, Kaufablauf, Synchronisierung oder Aktualisierungsanfragen
Der Coverage ist ein Taschenlampenlicht, nicht ein Ziel
Coverage-Berichte sind nützlich, wenn sie Ihnen helfen, ungetestete Zweige in wichtigen Logik zu erkennen. Sie werden schädlich, wenn Teams Coverage-Prozentsätze für ihren eigenen Willen verfolgen.
Ein Login-Validator mit sorgfältig ausgearbeiteten Edge-Fall-Tests liefert mehr Wert als ein abgedeckter Datei voller trivialer Behauptungen. Das ist besonders wahr für input-reiche code wie Formulare, Parser, Datumlogik und Berechtigungsprüfungen. Wenn Ihr Team die Qualität um die Validierung schwerpunkthafter UI herum schärft, ist diese Anleitung zum Mastering Frontend-Formularvalidierung eine gute Ergänzung zur Einheitsteststrategie.
Verhaltensvor-Tests überleben Refaktorisierungen
Auf eine zuverlässige Suite sollte es Sie ermöglichen, die Internen ohne die Hälfte der Tests neu zu schreiben. Der einfachste Weg, um dorthin zu gelangen, ist, zu behaupten beobachtbare Verhalten anstatt Implementierungsdetails.
Verwendungsfälle, die gut halten:
- Grenzwerte wie leerer Eingabe, nullartige Werte, ungültige Typen und überdimensionierte Zeichenfolgen
- Ausgänge des Domänenbereichs wie „Zugriffe verweigert, da die erforderliche Berechtigung fehlt“
- Zustandsübergänge wie „Update als ausstehend markiert, nachdem die Metadaten nach dem Download validiert wurden“
Verwendungsfälle, die oft verrotten:
- Internen Hilfsfunkaufrufe untersuchen
- Methodenaufrufsequenzierung behauptet
- Jede Schicht in der Aufrufkette wird simuliert
Für App-Teams, die disziplinierte Release-Prozesse entwickeln, ist der Artikel von Capgo zu "Qualitätssicherung von Apps" nützlich, weil er das Testen mit der breiteren Release-Pipeline verbindet. Qualitätssicherung von Apps ist nützlich, weil es das Testen mit der breiteren Release-Pipeline verbindet.
Testen für CI, Capacitor, und Electron-Apps
Ein Test, der nur auf einem Entwickler-Computer läuft, ist kein Sicherheitsnetz. Es ist eine lokale Gewohnheit.
CI wandelt JavaScript-Arbeit in Team-Infrastruktur um. Jeder Push, Pull-Request oder Release-Zweig kann dieselben Befehle mit denselben Erwartungen ausführen. Diese Konsistenz ist bei Capacitor- und Electron-Projekten noch wichtiger, da sich die Umgebungsdrift zu subtilen Fehlern verhält.
Setze CI als Standardausführungspfad
Zumindest sollte deine CI die Abhängigkeiten installieren und die Einheitssuite auf jedem Änderungssatz ausführen. Halte den Befehl so identisch wie möglich mit der lokalen Entwicklung.
Ein grundlegender GitHub-Actions-Auftrag kann so klein wie dieser sein:
name: test
on: [push, pull_request]
jobs:
unit:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test
Das reicht aus, um fehlerhafte Importe, fehlende Behauptungen und zufällige Plattformannahmen vor dem Hineinlaufen in die Hauptversion zu erkennen.
For mobile Teams, die über automatisierte Pipelines liefern, hat Capgo eine praktische Anleitung zum Einrichten von CI/CD für Capacitor-Apps.
Testen von Capacitor-Plugin-Interaktionen
Die falsche Art, Capacitor-code zu unit testen, ist, native Plugins direkt in jede Dienstinstanz zu pullen. Das koppelt Ihre Test-Suite an die Plattformbrücke.
Die bessere Muster ist eine dünne Abstraktion:
// deviceStorage.js
async function saveFile(filesystem, path, data) {
return filesystem.writeFile({ path, data });
}
module.exports = { saveFile };
// draftService.js
async function persistDraft(storage, draft) {
await storage.save('draft.json', JSON.stringify(draft));
return { saved: true };
}
module.exports = { persistDraft };
// draftService.test.js
const { persistDraft } = require('./draftService');
test('persists a serialized draft', async () => {
const storage = {
save: jest.fn().mockResolvedValue(undefined)
};
const result = await persistDraft(storage, { title: 'Hello' });
expect(result).toEqual({ saved: true });
});
Die gleiche Idee gilt für die Kamera-Zugriff, biometrische Anfragen, Push-Token-Registrierung und Netzwerkstatus. Halten Sie Plugin-Aufrufe in Adapters. Testen Sie die App-Logik gegen Schnittstellen, die Sie steuern.
Testen von Electron-Haupt-Renderer und IPC code
Elektron-Apps haben zwei wichtige Schnittstellen: Hauptprozess code und Renderer-Prozess code. Blenden Sie sie in Tests nicht aus.
A zuverlässige Konfiguration trennt normalerweise:
- Einheitstests für Renderer zur Sichtbarkeit, Zustand, Formatierung und Geschäftslogik auf der Benutzeroberfläche
- Einheitstests für den Hauptprozess zur Menüverwaltung, Dateibearbeitung und Lebenszyklusentscheidungen
- Vertragsprüfungen für IPC zur Nachrichtenform und erwarteten Antworten
Beispiel für eine IPC-Wrapper:
// ipcGateway.js
function sendSettings(ipcRenderer, payload) {
ipcRenderer.send('settings:update', payload);
}
module.exports = { sendSettings };
// ipcGateway.test.js
const { sendSettings } = require('./ipcGateway');
test('sends settings update over ipc', () => {
const ipcRenderer = { send: jest.fn() };
sendSettings(ipcRenderer, { theme: 'dark' });
expect(ipcRenderer.send).toHaveBeenCalledWith('settings:update', { theme: 'dark' });
});
Wenn Sie später die interne Implementierung von einem Helper zu einem anderen ändern, hält sich dieser Test noch immer, da er die verhaltensrelevanten Aspekte überprüft. Das ist der Standard, den Sie auf Desktop- und Mobilgeräten erreichen möchten code.
Häufig gestellte Fragen zum JavaScript-Einheitstesten
Was ist der Unterschied zwischen Einheitstests und E2E-Tests
A Einheitstest überprüft einen kleinen Logikteil isoliert. Ein Integrations-Test überprüft, ob einige Komponenten oder Dienste korrekt zusammenarbeiten. Ein End-to-End-Test übt eine Benutzerreise durch das laufende Anwendungsprogramm aus.
Verwenden Sie Einheitstests für schnelles Vertrauen in Geschäftsregeln. Verwenden Sie Integrations-Tests für Scharniere wie Speicher, Plugin-Wrapper und IPC. Verwenden Sie E2E-Tests sparsam für die Workflows, die ernsthafte Schäden verursachen würden, wenn sie zusammenbrechen.
Sollten wir uns auf volle Abdeckung richten
Nein. Vollständige Abdeckung kann Teams dazu zwingen, sich auf niedrigwertige Tests zu konzentrieren.
Die Abdeckung ist nützlich, wenn sie riskante code offenlegt, die niemand ausprobiert hat. Sie ist nicht nützlich, wenn Ingenieure nur flache Behauptungen hinzufügen, um ein Dashboard zu befriedigen. Wenn Ihr Suite anfällig ist, wird mehr Abdeckung sie nicht retten.
Wie fügen wir Tests zu einem bestehenden Codebase hinzu
Beginnen Sie, wo Änderungen bereits stattfinden. Ersticken Sie die Mannschaft nicht und verkünden Sie eine riesige Überarbeitung der Teststrategie.
Eine praktische Sequenz sieht so aus:
- Schützen Sie die aktiven code zuerst indem Sie Tests zu den Modulen hinzufügen, die Sie während der Feature-Arbeit oder Bug-Fixes berühren
- Entfernen Sie reine Logik aus schwer zu testenden Dateien, damit Geschäftsregeln ohne Framework- oder Laufzeit-Rauschen getestet werden können
- Fügen Sie Schweißringe um native Plugins, Netzwerkclients, Dateisystemaufrufe und Electron-IPC um
- Weigern Sie sich gegen verderbliche Muster wenn Sie Mocks einführen. Leitfaden aus JavaScript-Testbest Practices ist hier besonders nützlich, da er das oft übersehene Problem der Über-Mockung und die daraus folgenden verderblichen Tests hervorhebt
Das Ziel ist nicht die sofortige Vollständigkeit. Es ist ein stetiger Fortschritt in den Bereichen, in denen Rückschritte dem Team am meisten Kosten
Wenn Ihr Team Apps mit Capacitor oder Electron entwickelt und ein saubereres Release-Prozess um JavaScript-Änderungen benötigt, Capgo ist eine Option, die man in Betracht ziehen sollte. Es bietet live aktualisierte Updates für CapacitorJS- und Electron-Apps, mit Rollout-Kontrollen und -Beobachtungsmöglichkeiten, damit Teams solide Einheitstests mit einem sicheren Weg zum Versand von Web-Bundle-Änderungen ohne auf jede Korrektur warten zu müssen, die Store-Überprüfung für jede Reparatur durchführen können.