आपके टेस्ट झूठ बोल रहे हैं? म्यूटेशन टेस्टिंग का समय
\n\nआप यूनिट-टेस्ट लिखते हैं, कोड कवरेज (code coverage) आँखों को भाता है — 85%, 90%, लेकिन बग्स फिर भी प्रोडक्शन में निकल आते हैं? परिचित दर्द। क्लासिकल कवरेज मेट्रिक (line/branch coverage) मूल रूप से यह माप है कि कोड की कौन सी पंक्तियाँ चलाई गईं। लेकिन यह कुछ नहीं बताता कि टेस्ट तर्क को कितनी अच्छी तरह जाँचते हैं। वे बस पंक्तियों पर "दौड़" सकते हैं, परिणाम की सटीकता की जाँच किए बिना।
\n\nयहाँ पर mutation testing (म्यूटेशन टेस्टिंग) मंच पर आता है। यह आपके कोड के लिए एक वैक्सीन के इंजेक्शन जैसा है: हम जानबूझकर प्रोग्राम में छोटे "वायरस" (म्यूटेशन) डालते हैं, और देखते हैं कि क्या हमारे टेस्ट उन्हें मारते हैं। यदि === को !== में बदलने के बाद टेस्ट फेल नहीं होता — तो आपके टेस्ट कमजोर हैं। pythonlib.ru पर इस लेख में, हम समझेंगे कि जावास्क्रिप्ट प्रोजेक्ट में mutation testing को कैसे शामिल करें, ताकि आपका कोड वास्तव में विश्वसनीय बने।
सरल शब्दों में म्यूटेशन टेस्टिंग क्या है
\n\nकल्पना करें कि आप एक QA-इंजीनियर हैं, जो चुपके से डेवलपर के कोड में एक लाइन बदल देता है:
\n\n// था\nif (user.age >= 18) { allowAccess(); }\n\n// हो गया (म्यूटेशन)\nif (user.age > 18) { allowAccess(); }\n\nयदि इस बदलाव के बाद भी यूनिट-टेस्ट हरे हैं — तो टेस्ट सीमा शर्त 18 की जाँच नहीं कर रहे हैं। म्यूटेशन फ्रेमवर्क ऐसे हज़ारों बदलाव स्वचालित रूप से करता है और एक रिपोर्ट देता है: कितने म्यूटेशन बच गए (survived)। जितने कम बचे हुए म्यूटेंट — उतने ही विश्वसनीय आपके टेस्ट।
जावास्क्रिप्ट में म्यूटेशन के मुख्य प्रकार:
\n- \n
- तुलना ऑपरेटरों का बदलना:
>→>=,===→!==\n - फ़ंक्शन कॉल को हटाना:
validate()→ खाली स्ट्रिंग \n - संख्यात्मक लिटरल बदलना:
0→1,100→0\n - तार्किक शर्तों को उलटना:
if (isActive)→if (!isActive)\n - स्ट्रिंग मानों को बदलना (कम बार, लेकिन होता है) \n
क्यों code coverage एक झूठी सुरक्षा है
\n\nकई जावास्क्रिप्ट डेवलपर 100% कोड कवरेज से भ्रमित हो जाते हैं। आइए एक वास्तविक उदाहरण देखें:
\n\n// फ़ंक्शन जो छूट निर्धारित करता है\nfunction getDiscount(price, isPremium) {\n if (price > 100 && isPremium) {\n return price * 0.8;\n }\n return price;\n}\n\nऔर "आदर्श" टेस्ट:
\n\ntest('गैर-प्रीमियम के लिए मूल्य वापस करना चाहिए', () => {\n expect(getDiscount(50, false)).toBe(50);\n});\n\ntest('कम मूल्य वाले प्रीमियम के लिए मूल्य वापस करना चाहिए', () => {\n expect(getDiscount(50, true)).toBe(50);\n});\n\nकवरेज: 100% पंक्तियाँ, 100% शाखाएँ। लेकिन म्यूटेशन price > 100 → price >= 100 बच जाएगा! टेस्ट सीमा मान 100.01 या ठीक 100 की जाँच नहीं करते। Mutation testing तुरंत इस "अंधे धब्बे" को उजागर करेगा।
टूल नंबर 1: जावास्क्रिप्ट के लिए Stryker Mutator
\n\nJS दुनिया में म्यूटेशन टेस्टिंग के लिए सबसे लोकप्रिय और परिपक्व टूल Stryker Mutator (या बस Stryker) है। यह Jest, Mocha, Jasmine, Karma को सपोर्ट करता है और TypeScript के साथ काम करता है।
\n\nस्थापना और त्वरित शुरुआत
\n\nStryker को अपने प्रोजेक्ट में वैश्विक या स्थानीय रूप से स्थापित करें:
\n\nnpm install --save-dev @stryker-mutator/core @stryker-mutator/jest-runner\n\nएक कॉन्फ़िगरेशन फ़ाइल stryker.conf.json बनाएँ:
{\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म्यूटेशन चलाएँ