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

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

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

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

आपके टेस्ट झूठ बोल रहे हैं, और आपको पता भी नहीं

\n\n

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

\n\n

समस्या यह है कि क्लासिकल कोड कवरेज एक भ्रम है। यह दिखाता है कि कोड की कौन सी पंक्तियाँ निष्पादित हुईं, लेकिन मुख्य प्रश्न का उत्तर नहीं देता: क्या टेस्ट वास्तव में लॉजिक की जाँच कर रहे हैं? यहीं पर mutation testing आता है — एक ऐसी तकनीक जो बेरहमी से आपके कोड को "तोड़ती" है, ताकि यह जाँच सके कि आपके टेस्ट कितने अच्छे हैं।

\n\n

इस लेख में, हम समझेंगे कि जावा में म्यूटेशन टेस्टिंग क्या है, यह कैसे काम करता है, और PIT (Pitest) टूल का उपयोग करके वास्तविक उदाहरण दिखाएँगे। आप सीखेंगे कि अपने टेस्ट को "रिपोर्ट में टिक" से बग्स के खिलाफ वास्तविक सुरक्षा में कैसे बदलें।

\n\n

mutation testing क्या है और यह क्यों महत्वपूर्ण है?

\n\n

Mutation testing (या म्यूटेशन टेस्टिंग) टेस्ट की गुणवत्ता का मूल्यांकन करने की एक विधि है, जिसमें स्रोत कोड में छोटे, जानबूझकर गलत बदलाव किए जाते हैं (जिन्हें म्यूटेशन कहा जाता है)। इसके बाद आपके टेस्ट चलाए जाते हैं। यदि कम से कम एक टेस्ट फेल होता है — म्यूटेंट "मारा गया", टेस्ट ने काम किया। यदि टेस्ट पास हो जाते हैं — म्यूटेंट "बच गया", और यह एक चेतावनी है।

\n\n

एक सरल उपमा: आप जाँच रहे हैं कि आपका अलार्म चोरों को कितनी अच्छी तरह पकड़ता है। आप एक "चोर" (म्यूटेंट) रखते हैं और देखते हैं कि अलार्म (टेस्ट) बजता है या नहीं। यदि चोर शांति से चला जाता है — अलार्म बेकार है।

\n\n

code coverage एक खराब संकेतक क्यों है?

\n\n

ऐसे कोड की कल्पना करें:

\n\n
public boolean isAdult(int age) {\n    if (age >= 18) {\n        return true;\n    }\n    return false;\n}
\n\n

और टेस्ट:

\n\n
@Test\nvoid testIsAdult() {\n    assertTrue(isAdult(18));\n}
\n\n

कोड कवरेज 100% दिखाएगा (क्या if-else की दोनों शाखाएँ निष्पादित हुईं?) नहीं! केवल true शाखा निष्पादित हुई। लेकिन टेस्ट हरा है। अब कल्पना करें कि किसी ने गलती से शर्त को age > 21 में बदल दिया। टेस्ट फिर भी पास होगा, क्योंकि 18 > 21 false है, और assertTrue true की उम्मीद करता है। बग प्रोडक्शन में चला जाएगा।

\n\n

म्यूटेशन टेस्टिंग तुरंत ऐसी स्थिति को पकड़ लेगी, एक म्यूटेंट बनाकर जो >= को > में बदलता है या शर्त को उलट देता है।

\n\n

mutation testing कैसे काम करता है: सरल सिद्धांत

\n\n

प्रक्रिया तीन चरणों में होती है:

\n\n
    \n
  1. म्यूटेंट का निर्माण। टूल (जैसे, PIT) आपके कोड के कई संस्करण बनाता है जिनमें छोटे बदलाव होते हैं: ऑपरेटर बदलना, मेथड कॉल हटाना, शर्तों को उलटना।
  2. \n
  3. टेस्ट चलाना। प्रत्येक म्यूटेंट के लिए आपके यूनिट टेस्ट चलाए जाते हैं।
  4. \n
  5. परिणामों का विश्लेषण। यदि टेस्ट फेल होता है — म्यूटेंट मारा गया। यदि पास होता है — जीवित। मारे गए म्यूटेंट का प्रतिशत mutation score (म्यूटेशन स्कोर) कहलाता है।
  6. \n
\n\n

अच्छा संकेतक: 80-90% मारे गए म्यूटेंट। इससे कम कुछ भी टेस्ट को फिर से लिखने का कारण है।

\n\n

PIT के साथ जावा में व्यावहारिक उदाहरण

\n\n

आइए एक वास्तविक उदाहरण लें। मान लीजिए, हमारे पास छूट की गणना के लिए एक सेवा है:

\n\n
public class DiscountService {\n    public double calculateDiscount(double amount, boolean isPremium) {\n        double discount = 0.0;\n\n        if (amount > 100) {\n            discount = 0.1; // 10% छूट\n        }\n\n        if (isPremium) {\n            discount += 0.05; // अतिरिक्त 5%\n        }\n\n        // छूट 30% से अधिक नहीं हो सकती\n        if (discount > 0.3) {\n            discount = 0.3;\n        }\n\n        return discount;\n    }\n}
\n\n

एक सरल टेस्ट लिखें:

\n\n
import org.junit.jupiter.api.Test;\nimport static org.junit.jupiter.api.Assertions.*;\n\nclass DiscountServiceTest {\n\n    private final DiscountService service = new                

ब्लॉग

पुस्तक अनुशंसाएँ