Mutation Testing in JavaScript: Unsichtbare Bugs aufspüren

Online Python-Trainer für Anfänger

Lernen Sie Python einfach ohne theoretische Überlastung. Lösen Sie praktische Aufgaben mit automatischer Überprüfung und schreiben Sie Code direkt im Browser.

Kurs starten

Lügen Ihre Tests? Zeit für Mutation Testing

\n\n

Sie schreiben Unit-Tests, die Code Coverage sieht gut aus – 85%, 90% – und trotzdem tauchen Bugs in der Produktion auf? Ein bekanntes Problem. Die klassische Metrik (Line/Branch Coverage) misst im Grunde nur, welche Codezeilen ausgeführt wurden. Sie sagt aber nichts darüber aus, wie gründlich die Tests die Logik prüfen. Sie können einfach die Zeilen "durchlaufen", ohne die Korrektheit des Ergebnisses zu verifizieren.

\n\n

Hier kommt Mutation Testing ins Spiel. Stellen Sie es sich wie eine Impfung für Ihren Code vor: Wir schleusen absichtlich kleine "Viren" (Mutationen) in das Programm ein und beobachten, ob unsere Tests sie erkennen. Fallen die Tests nicht, nachdem wir === in !== geändert haben – sind Ihre Tests schwach. In diesem Artikel auf pythonlib.ru zeigen wir Ihnen, wie Sie Mutation Testing in Ihr JavaScript-Projekt integrieren, um Ihren Code wirklich robust zu machen.

\n\n

Was ist Mutation Testing? Einfach erklärt

\n\n

Stellen Sie sich vor, Sie sind ein QA-Ingenieur, der heimlich eine Zeile im Code des Entwicklers ändert:

\n\n
// Vorher\nif (user.age >= 18) { allowAccess(); }\n\n// Nachher (Mutation)\nif (user.age > 18) { allowAccess(); }
\n\n

Wenn die Unit-Tests nach dieser Änderung immer noch grün sind – dann prüfen die Tests den Grenzfall 18 nicht. Ein Mutations-Framework führt tausende solcher Änderungen automatisch durch und erstellt einen Bericht: Wie viele Mutationen haben überlebt (survived). Je weniger überlebende Mutanten, desto zuverlässiger Ihre Tests.

\n\n

Die wichtigsten Mutationsarten in JavaScript:

\n
    \n
  • Änderung von Vergleichsoperatoren: > → >=, === → !==
  • \n
  • Entfernen von Funktionsaufrufen: validate() → leere Zeile
  • \n
  • Änderung numerischer Literale: 0 → 1, 100 → 0
  • \n
  • Invertieren von logischen Bedingungen: if (isActive) → if (!isActive)
  • \n
  • Ersetzen von Zeichenketten (seltener, aber möglich)
  • \n
\n\n

Warum Code Coverage eine trügerische Sicherheit ist

\n\n

Viele JavaScript-Entwickler wiegen sich in falscher Sicherheit bei 100% Code Coverage. Sehen wir uns ein reales Beispiel an:

\n\n
// Funktion zur Rabattberechnung\nfunction getDiscount(price, isPremium) {\n    if (price > 100 && isPremium) {\n        return price * 0.8;\n    }\n    return price;\n}
\n\n

Und der "perfekte" Test:

\n\n
test('should return price for non-premium', () => {\n    expect(getDiscount(50, false)).toBe(50);\n});\n\ntest('should return price for premium with low price', () => {\n    expect(getDiscount(50, true)).toBe(50);\n});
\n\n

Coverage: 100% Zeilen, 100% Zweige. Aber die Mutation price > 100 → price >= 100 wird überleben! Die Tests prüfen den Grenzwert 100.01 oder exakt 100 nicht. Mutation Testing deckt diese "blinden Flecken" sofort auf.

\n\n

Tool Nr. 1: Stryker Mutator für JavaScript

\n\n

Das bekannteste und ausgereifteste Tool für Mutation Testing in der JS-Welt ist Stryker Mutator (oder einfach Stryker). Es unterstützt Jest, Mocha, Jasmine, Karma und funktioniert mit TypeScript.

\n\n

Installation und Schnellstart

\n\n

Installieren Sie Stryker global oder lokal in Ihrem Projekt:

\n\n
npm install --save-dev @stryker-mutator/core @stryker-mutator/jest-runner
\n\n

Erstellen Sie eine Konfigurationsdatei stryker.conf.json:

\n\n
{\n  "$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json",\n  "packageManager": "npm",\n  "reporters": ["html", "clear-text", "progress"],\n  "testRunner": "jest",\n  "coverageAnalysis": "perTest",\n  "thresholds": {\n    "high": 80,\n    "low": 60,\n    "break": 50\n  }\n}
\n\n

Starten Sie den Mutations

Blogs

Buchempfehlungen