सामान्य परीक्षण झूठ क्यों बोलते हैं और आप उन पर विश्वास क्यों करते हैं
\n\nकल्पना करें: आपने एक फ़ंक्शन लिखा, उसे तीन unit-टेस्ट से कवर किया। हरी टिक। CI पास हो जाता है। प्रोडक्शन — बग। परिचित लगता है?
\n\nक्लासिकल यूनिट-टेस्ट की समस्या यह है कि वे विशिष्ट उदाहरणों की जाँच करते हैं। आप स्वयं इनपुट डेटा सोचते हैं और स्वयं ही अपेक्षित परिणाम लिखते हैं। यह उस परीक्षा की तरह है जहाँ छात्र स्वयं प्रश्नपत्र बनाता है। देर-सबेर आप एक सीमांत मामला चूक जाएंगे — null, खाली सूची, ऋणात्मक संख्या या Unicode वर्णों वाली स्ट्रिंग।
\n\nयहाँ पर प्रॉपर्टी-आधारित परीक्षण (या गुण-आधारित परीक्षण) मंच पर आता है। यह लिखने के बजाय कि "यदि 5 पास करें, तो 25 वापस आना चाहिए", आप एक गुण तैयार करते हैं: "किसी भी पूर्णांक के लिए, वर्ग हमेशा गैर-ऋणात्मक होता है"। और फ्रेमवर्क स्वयं सैकड़ों यादृच्छिक मान उत्पन्न करता है और इस गुण की जाँच करता है।
\n\nइस लेख में, हम देखेंगे कि Kotlin में प्रॉपर्टी-आधारित परीक्षण का उपयोग Kotest लाइब्रेरी के साथ कैसे करें। आप सीखेंगे कि विश्वसनीय परीक्षण कैसे लिखें, शुरुआती चरणों में बग कैसे ढूंढें और रिफैक्टरिंग से डरना कैसे बंद करें। यह केवल उबाऊ सिद्धांत नहीं है — हम वास्तविक कोड लिखेंगे जिसे आप तुरंत अपने प्रोजेक्ट में लागू कर सकते हैं।
\n\nप्रॉपर्टी-आधारित परीक्षण क्या है और Kotlin क्यों?
\n\nयह विचार नया नहीं है — इसे 1999 में Haskell के लिए QuickCheck लाइब्रेरी ने लोकप्रिय बनाया था। लेकिन अब, backend-सिस्टम और माइक्रोसर्विसेज की बढ़ती जटिलता के साथ, प्रॉपर्टी-आधारित परीक्षण डेवलपर के स्टैक में must-have बन रहा है।
\n\nKotlin इस दृष्टिकोण के लिए आदर्श भाषा है। क्यों?
\n\n- \n
- कार्यात्मक क्षमताएँ: लैम्ब्डा, extension-फ़ंक्शन, इम्यूटेबिलिटी — ये सब स्वच्छ गुण लिखना आसान बनाते हैं। \n
- Kotest — एक शक्तिशाली फ्रेमवर्क है जो आउट-ऑफ-द-बॉक्स प्रॉपर्टी-आधारित परीक्षण, जनरेटर और Shrinking (फेल होने वाले उदाहरण को छोटा करने का एल्गोरिदम) का समर्थन करता है। \n
- Java के साथ संगतता: आप Java में लिखे legacy-कोड का परीक्षण उन्हीं दृष्टिकोणों का उपयोग करके कर सकते हैं। \n
चलिए सीधे मुद्दे पर आते हैं। नीचे एक उदाहरण है जो परीक्षण के बारे में आपकी सोच बदल देगा।
\n\n5 मिनट में पहला प्रॉपर्टी-आधारित परीक्षण
\n\nमान लीजिए, हमारे पास एक फ़ंक्शन है जो जाँचता है कि स्ट्रिंग पैलिंड्रोम है या नहीं:
\n\nfun isPalindrome(s: String): Boolean {\n val cleaned = s.filter { it.isLetterOrDigit() }.lowercase()\n return cleaned == cleaned.reversed()\n}\n\nसामान्य परीक्षण इस तरह दिखता है:
\n\n@Test\nfun `test known palindromes`() {\n assertTrue(isPalindrome("A man, a plan, a canal: Panama"))\n assertTrue(isPalindrome("racecar"))\n assertFalse(isPalindrome("hello"))\n}\n\nसब कुछ काम करता है। लेकिन क्या होगा यदि इनपुट डेटा में स्पेस, अंक या प्रतीक हों? और यदि स्ट्रिंग खाली हो? और यदि वह केवल स्पेस से बनी हो?
\n\nअब Kotest का उपयोग करके एक प्रॉपर्टी-आधारित परीक्षण लिखते हैं:
\n\nimport io.kotest.core.spec.style.StringSpec\nimport io.kotest.property.forAll\nimport io.kotest.property.arbitrary.string\n\nclass PalindromePropertyTest : StringSpec({\n "कोई भी स्ट्रिंग जो सफाई से गुज़री है, वह स्वयं के लिए पैलिंड्रोम होनी चाहिए" {\n forAll<String> { original ->\n val cleaned = original.filter { it.isLetterOrDigit() }.lowercase()\n isPalindrome(cleaned) == true\n }\n }\n})\n\nयहाँ क्या हो रहा है? forAll<String> यादृच्छिक स्ट्रिंग उत्पन्न करता है: खाली, स्पेस वाली, Unicode वाली, अंकों वाली। और प्रत्येक के लिए गुण की जाँच करता है। यदि कोई एक स्ट्रिंग भी कथन का उल्लंघन करती है — परीक्षण फेल हो जाएगा, और Kotest न्यूनतम पुनरुत्पादन योग्य उदाहरण दिखाएगा।
पहले से ही इस चरण में आप बग ढूंढ सकते हैं। उदाहरण के लिए, यदि स्ट्रिंग केवल स्पेस से बनी है — filter एक खाली स्ट्रिंग लौटाएगा, और isPalindrome("") true लौटाएगा। सामान्य परीक्षण इसे अनदेखा कर देता।