Kotlin में म्यूटेशन टेस्टिंग: ऐसा कोड लिखना जो बदलावों से न डरे

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

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

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

कोड कवरेज (code coverage) एक जाल क्यों है, और म्यूटेशन टेस्टिंग (mutation testing) मुक्ति क्यों है

\n\n

एक स्थिति की कल्पना करें: Kotlin में आपका प्रोजेक्ट 95% टेस्ट से कवर है। CI हरा है, मैनेजर खुश है, कोड प्रोडक्शन में जा रहा है। और एक हफ्ते बाद — प्रोडक्शन में बग। परिचित लगता है? सबसे अधिक संभावना है, आपके टेस्ट बस चलते हैं, लेकिन लॉजिक की जाँच नहीं करते। यहीं पर mutation testing (म्यूटेशन टेस्टिंग) आता है — एक ऐसी तकनीक जो टेस्ट को "नकली काम" नहीं करने देती।

\n\n

इस लेख में, हम समझेंगे कि Kotlin में mutation testing क्या है, यह कैसे काम करता है, और लोकप्रिय टूल Pitest की मदद से इसे प्रोजेक्ट में कैसे शामिल करें। आप जानेंगे कि 100% कोड कवरेज गुणवत्ता की गारंटी क्यों नहीं है, और म्यूटेशन टेस्टिंग वास्तव में विश्वसनीय टेस्ट लिखने में कैसे मदद करता है।

\n\n

म्यूटेशन टेस्टिंग क्या है? बिल्लियों के उदाहरण से समझाएँ

\n\n

मान लीजिए, आपने एक फंक्शन लिखा है जो यह निर्धारित करता है कि बिल्ली दरवाजे से निकल सकती है या नहीं:

\n\n
fun canCatFitThroughDoor(catWidth: Int, doorWidth: Int): Boolean {\n    return catWidth <= doorWidth\n}
\n\n

आपने एक टेस्ट लिखा:

\n\n
@Test\nfun `30 चौड़ाई की बिल्ली 40 चौड़ाई के दरवाजे से निकलती है`() {\n    assertTrue(canCatFitThroughDoor(30, 40))\n}
\n\n

कवरेज — 100%। लेकिन क्या होगा अगर कोई गलती से <= को < में बदल दे? टेस्ट फिर भी पास हो जाएगा! म्यूटेशन टेस्टिंग स्वचालित रूप से कोड में ऐसे "छोटे ब्रेकडाउन" (म्यूटेशन) डालता है और जाँचता है कि क्या कम से कम एक टेस्ट फेल होता है। अगर टेस्ट फेल नहीं होता — तो आपके टेस्ट इस त्रुटि को नहीं पकड़ पाते। इसे ही Kotlin में म्यूटेशन टेस्टिंग कहते हैं।

\n\n

म्यूटेशन टेस्टिंग कैसे काम करता है: ऑपरेटरों से लेकर "जीवित" म्यूटेंट तक

\n\n

टूल (उदाहरण के लिए, Kotlin के लिए Pitest) म्यूटेंट बनाता है — आपके कोड के वे संस्करण जिनमें एक बदलाव होता है। ये हैं विशिष्ट म्यूटेशन:

\n\n
    \n
  • तुलना ऑपरेटरों का बदलना: > → >=, == → !=
  • \n
  • शर्तों को उलटना: if (a > b) → if (a <= b)
  • \n
  • मेथड कॉल हटाना: someMethod() → खाली
  • \n
  • रिटर्न वैल्यू बदलना: true → false
  • \n
  • संख्याएँ बदलना: 10 → 11 या 0
  • \n
\n\n

म्यूटेंट बनाने के बाद, आपके सभी टेस्ट चलाए जाते हैं। परिणाम तीन श्रेणियों में बाँटे जाते हैं:

\n\n
    \n
  • मारे गए म्यूटेंट (Killed) — टेस्ट फेल हुए, म्यूटेशन का पता चला। बढ़िया!
  • \n
  • जीवित म्यूटेंट (Survived) — टेस्ट पास हुए, भले ही कोड बदल गया हो। चेतावनी का संकेत।
  • \n
  • कवर किए गए लेकिन मारे नहीं गए (Covered but not killed) — टेस्ट चले, लेकिन बदलाव पर ध्यान नहीं दिया।
  • \n
\n\n

आपका लक्ष्य यह सुनिश्चित करना है कि जीवित म्यूटेंट जितना संभव हो उतने कम हों (आदर्श रूप से 0)। यही Kotlin कोड का म्यूटेशन टेस्टिंग है।

\n\n

Pitest: Kotlin के लिए मुख्य टूल

\n\n

JVM भाषाओं (Java, Kotlin) के लिए, डी-फैक्टो मानक Pitest (PIT Mutation Testing) है। यह pitest-kotlin प्लगइन के माध्यम से Kotlin को सपोर्ट करता है। इसे Gradle में जोड़ने का तरीका यहाँ है:

\n\n
plugins {\n    id("info.solidsoft.pitest") version "1.15.0"\n}\n\npitest {\n    targetClasses.set(listOf("com.myapp.*")) // किन क्लासेज को म्यूटेट करना है\n    targetTests.set(listOf("com.myapp.*"))    // कौन से टेस्ट चलाने हैं\n    threads.set(4)                            // समानांतर थ्रेड\n    outputFormats.set(listOf("XML", "HTML"))  // रिपोर्ट\n    mutationThreshold.set(80)                 // मारे गए म्यूटेंट का न्यूनतम प्रतिशत\n    timeoutConstInMillis.set(10000)           // टेस्ट के लिए टाइमआउट\n}\n\ndependencies {\n    testImplementation("org.pitest:pitest-kotlin:1.15.0")\n}
\n\n

एक कमांड से चलाएँ:

\n\n
./gradlew pitest
\n\n

निष्पादन के बाद, build/reports/pites में

ब्लॉग

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