C# में म्यूटेशन टेस्टिंग: कोड को बेहतर बनाने के लिए उसे तोड़ना

शुरुआती लोगों के लिए ऑनलाइन Python प्रशिक्षक

Python आसानी से सीखें बिना सिद्धांत के बोझ के। स्वचालित जांच के साथ व्यावहारिक कार्य हल करें और ब्राउज़र में सीधे कोड लिखें।

पाठ्यक्रम शुरू करें

जब टेस्ट पास होते हैं, लेकिन कोड फिर भी 'टूटा हुआ' होता है

\n\n

एक स्थिति की कल्पना करें: आपने C# प्रोजेक्ट के लिए मॉड्यूलर टेस्ट लिखे, dotnet test हरी बत्ती दिखाता है, कोड कवरेज (code coverage) 85% है। टीम खुश है, CI/CD पूरी तरह से चल रहा है। लेकिन एक महीने बाद production में एक बग आ जाता है, जिसे यूनिट-टेस्ट को पकड़ना चाहिए था। परिचित लगता है?

\n\n

समस्या यह है कि कोड कवरेज (code coverage) एक भ्रामक मीट्रिक है। यह दिखाता है कि कोड की कौन सी पंक्तियाँ प्रभावित हुईं, लेकिन यह जाँच नहीं करता कि जाँच स्वयं कितनी गुणवत्तापूर्ण हैं। आपके पास 100% कवरेज हो सकता है, लेकिन एक भी सार्थक assert नहीं। यहीं पर C# में म्यूटेशन टेस्टिंग आती है - एक ऐसी तकनीक जो आपके कोड को 'तोड़ती' है ताकि यह जाँच सके कि आपके टेस्ट कितनी अच्छी तरह से त्रुटियाँ पकड़ सकते हैं।

\n\n

इस लेख में, हम समझेंगे कि mutation testing क्या है, इसे Stryker.NET के साथ .NET प्रोजेक्ट्स में कैसे लागू करें, और यह किसी भी गंभीर C# डेवलपर के लिए क्यों must-have है।

\n\n

म्यूटेशन टेस्टिंग (Mutation Testing) क्या है?

\n\n

म्यूटेशन टेस्टिंग टेस्ट की गुणवत्ता का मूल्यांकन करने की एक विधि है, जो प्रोग्राम के स्रोत कोड में छोटे जानबूझकर बदलाव (म्यूटेशन) करने पर आधारित है। ऐसे प्रत्येक संशोधित कोड संस्करण को म्यूटेंट (mutant) कहा जाता है।

\n\n

तर्क सरल है:

\n
    \n
  • आपका production-कोड लिया जाता है।
  • \n
  • स्वचालित रूप से म्यूटेंट उत्पन्न होते हैं - उदाहरण के लिए, ऑपरेटर + को - से बदल दिया जाता है, शर्त if (x > 5) को if (x >= 5) में बदल दिया जाता है, और true को false में बदल दिया जाता है।
  • \n
  • आपके यूनिट-टेस्ट प्रत्येक म्यूटेंट के विरुद्ध चलाए जाते हैं।
  • \n
  • यदि टेस्ट विफल होता है - म्यूटेंट 'मारा गया' (killed)। अच्छा टेस्ट।
  • \n
  • यदि टेस्ट पास होता है - म्यूटेंट 'बच गया' (survived)। बुरा संकेत: आपके टेस्ट ने तर्क में बदलाव पर ध्यान नहीं दिया।
  • \n
\n\n

लक्ष्य मारे गए म्यूटेंट का उच्च प्रतिशत (आमतौर पर 80%+) प्राप्त करना है। यह एक वास्तविक गारंटी है कि आपके टेस्ट व्यवहार की जाँच कर रहे हैं, न कि केवल कोड पर 'दौड़' रहे हैं।

\n\n

कोड कवरेज (code coverage) अपर्याप्त क्यों है?

\n\n

C# में एक सरल उदाहरण पर विचार करें। मान लीजिए, हमारे पास एक विधि है जो जाँचती है कि कोई संख्या सम है या नहीं:

\n\n
public class MathUtils\n{\n    public bool IsEven(int number)\n    {\n        return number % 2 == 0;\n    }\n}
\n\n

और 100% कवरेज वाला 'आदर्श' टेस्ट:

\n\n
[Test]\npublic void IsEven_ShouldReturnTrueForEvenNumber()\n{\n    var utils = new MathUtils();\n    var result = utils.IsEven(4);\n    Assert.IsTrue(result);\n}
\n\n

टेस्ट हरा है, कवरेज 100% है। लेकिन क्या होगा अगर कोई गलती से (या जानबूझकर) विधि को return number % 2 == 1; में बदल दे? क्या हमारा एकमात्र टेस्ट विफल होगा? नहीं! यह संख्या 4 की जाँच करेगा (4 % 2 == 0, लेकिन अब विधि false लौटाएगी), assert विफल होगा - म्यूटेंट मारा जाएगा। सब ठीक है? रुकिए।

\n\n

और अगर कोड को return number % 2 != 1; में बदल दिया जाए? तार्किक रूप से यह वही है, लेकिन म्यूटेशन टेस्टिंग एक म्यूटेंट बनाएगी: return number % 2 != 0;। संख्या 4 के साथ हमारा टेस्ट अभी भी पास होगा (4 % 2 != 0 — false, विधि false लौटाएगी, लेकिन assert true की उम्मीद करता है — टेस्ट विफल होगा)। यहाँ सब ठीक है। लेकिन कल्पना करें कि हमने टेस्ट इस तरह लिखा:

\n\n
[Test]\npublic void IsEven_ShouldNotThrow()\n{\n    var utils = new MathUtils();\n    Assert.DoesNotThrow(() => utils.IsEven(4));\n}
\n\n

कवरेज अभी भी 100% है, लेकिन assert परिणाम की जाँच नहीं करता! अब कोई भी म्यूटेंट बच जाएगा। म्यूटेशन टेस्टिंग तुरंत दिखाएगी कि आपके टेस्ट खोखले हैं।

\n\n

C# में म्यूटेशन टेस्टिंग के लिए उपकरण

\n\n

.NET के लिए मुख्य और वास्तव में मानक उपकरण Stryker.NET है। यह एक open-source फ्रेमवर्क है जो किसी भी C# प्रोजेक्ट में आसानी से एकीकृत हो जाता है। यह xUnit, NUnit और MSTest का समर्थन करता है।

\n\n

अन्य उपकरण (कम लोकप्रिय):

\n