Mutation Testing en JavaScript : détectez les bugs invisibles

Formateur Python en ligne pour débutants

Apprenez Python facilement sans surcharge théorique. Résolvez des tâches pratiques avec vérification automatique et écrivez du code directement dans le navigateur.

Start Course

Vos tests mentent-ils ? Passez au mutation testing

\n\n

Vous écrivez des tests unitaires, la couverture de code (code coverage) est belle — 85 %, 90 %, mais les bugs refont surface en production ? Un scénario classique. La métrique de couverture traditionnelle (line/branch coverage) ne fait que mesurer quelles lignes de code ont été exécutées. Mais elle ne dit rien sur la qualité réelle de vos tests. Ceux-ci peuvent simplement "passer" sur les lignes sans vérifier la logique métier.

\n\n

C'est là qu'intervient le mutation testing (test de mutation). Pensez-y comme à un vaccin pour votre code : on introduit intentionnellement de petits "virus" (mutations) dans le programme, et on observe si nos tests les détectent. Si un test ne plante pas après avoir changé === en !==, c'est que vos tests sont trop faibles. Dans cet article sur pythonlib.fr, nous allons voir comment intégrer le mutation testing dans un projet JavaScript pour rendre votre code vraiment fiable.

\n\n

Qu'est-ce que le mutation testing en termes simples

\n\n

Imaginez que vous êtes un ingénieur QA qui modifie en secret une ligne de code du développeur :

\n\n
// Avant\nif (user.age >= 18) { allowAccess(); }\n\n// Après (mutation)\nif (user.age > 18) { allowAccess(); }
\n\n

Si après ce changement, les tests unitaires sont toujours verts, c'est qu'ils ne vérifient pas la condition limite 18. Un framework de mutation effectue des milliers de modifications de ce type automatiquement et génère un rapport : combien de mutations ont survécu (survived). Moins il y a de mutants survivants, plus vos tests sont robustes.

\n\n

Les principaux types de mutations en JavaScript :

\n
    \n
  • Modification des opérateurs de comparaison : > → >=, === → !==
  • \n
  • Suppression d'appels de fonctions : validate() → chaîne vide
  • \n
  • Modification des littéraux numériques : 0 → 1, 100 → 0
  • \n
  • Inversion de conditions booléennes : if (isActive) → if (!isActive)
  • \n
  • Remplacement de valeurs de chaînes (plus rare, mais possible)
  • \n
\n\n

Pourquoi la couverture de code est une fausse sécurité

\n\n

De nombreux développeurs JavaScript se laissent berner par une couverture de code à 100 %. Regardons un exemple concret :

\n\n
// Fonction qui calcule une réduction\nfunction getDiscount(price, isPremium) {\n    if (price > 100 && isPremium) {\n        return price * 0.8;\n    }\n    return price;\n}
\n\n

Et le test "parfait" :

\n\n
test('devrait retourner le prix pour un non-premium', () => {\n    expect(getDiscount(50, false)).toBe(50);\n});\n\ntest('devrait retourner le prix pour un premium avec petit prix', () => {\n    expect(getDiscount(50, true)).toBe(50);\n});
\n\n

Couverture : 100 % des lignes, 100 % des branches. Mais la mutation price > 100 → price >= 100 survivra ! Les tests ne vérifient pas la valeur limite 100.01 ou exactement 100. Le mutation testing mettra immédiatement en évidence cette "zone d'ombre".

\n\n

Outil n°1 : Stryker Mutator pour JavaScript

\n\n

L'outil le plus populaire et mature pour le mutation testing dans le monde JS est Stryker Mutator (ou simplement Stryker). Il prend en charge Jest, Mocha, Jasmine, Karma et fonctionne avec TypeScript.

\n\n

Installation et démarrage rapide

\n\n

Installez Stryker globalement ou localement dans votre projet :

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

Créez un fichier de configuration 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

Lancez le test de mutation

Blogs

Book Recommendations