परिचय: यूनिट-टेस्ट हर चीज़ से क्यों नहीं बचाते
\n\nकल्पना करें कि आपने एक ऐरे सॉर्टिंग फंक्शन लिखा है। आपने इसे दस यूनिट-टेस्ट से कवर किया: खाली ऐरे, एक एलिमेंट, पहले से सॉर्ट की गई सूची, उल्टा क्रम। टेस्ट हरे हैं। आप कोड को लेकर आश्वस्त हैं। लेकिन एक हफ्ते बाद प्रोडक्शन क्रैश हो जाता है — डुप्लिकेट और नकारात्मक संख्याओं वाले 1000 एलिमेंट के ऐरे पर। परिचित लगता है?
\n\nउदाहरणों के आधार पर पारंपरिक TypeScript परीक्षण (example-based testing) केवल उन परिदृश्यों की जाँच करता है जो आपने सोचे हैं। क्या होगा यदि बग उस संयोजन में छिपा हो जिसके बारे में आपने नहीं सोचा? यहाँ पर प्रॉपर्टी-आधारित परीक्षण (property-based testing) आता है — एक दृष्टिकोण जो स्वचालित रूप से हजारों यादृच्छिक इनपुट डेटा उत्पन्न करता है और आपके कोड के इनवेरिएंट की जाँच करता है।
\n\nइस लेख में, हम समझेंगे कि कैसे TypeScript में प्रॉपर्टी-आधारित परीक्षण को fast-check लाइब्रेरी के साथ लागू किया जाए, किन गुणों की जाँच करनी चाहिए और यह विकास के दृष्टिकोण को कैसे बदलता है।
\n\nप्रॉपर्टी-आधारित परीक्षण क्या है?
\n\nयह लिखने के बजाय:
\nit('सॉर्ट करता है [3, 1, 2] → [1, 2, 3]', () => {\n expect(sort([3, 1, 2])).toEqual([1, 2, 3]);\n});\n\n\nआप एक गुण (property) का वर्णन करते हैं — एक अभिकथन जो सभी सही इनपुट डेटा के लिए सत्य होना चाहिए:
\nit('सॉर्ट किया गया ऐरे एलिमेंट के क्रम को नहीं बदलता', () => {\n fc.assert(\n fc.property(fc.array(fc.integer()), (arr) => {\n const sorted = sort(arr);\n // गुण 1: लंबाई संरक्षित रहती है\n expect(sorted.length).toBe(arr.length);\n // गुण 2: मूल ऐरे का प्रत्येक एलिमेंट मौजूद है\n // गुण 3: ऐरे आरोही क्रम में सॉर्ट किया गया है\n for (let i = 1; i < sorted.length; i++) {\n expect(sorted[i - 1]).toBeLessThanOrEqual(sorted[i]);\n }\n })\n );\n});\n\n\nfast-check लाइब्रेरी स्वयं सैकड़ों यादृच्छिक ऐरे उत्पन्न करेगी (खाली, NaN वाले, दशमलव संख्याओं वाले, बड़े मानों वाले) और प्रत्येक पर आपका टेस्ट चलाएगी। यदि कोई भी विफल होता है — तो आपको समस्या के बारे में पता चल जाएगा।
\n\nTypeScript में इसकी आवश्यकता क्यों है?
\n\nTypeScript स्थैतिक टाइपिंग प्रदान करता है, लेकिन यह तर्क की शुद्धता की गारंटी नहीं देता। TypeScript का प्रॉपर्टी-आधारित परीक्षण "टाइप्स मैच होते हैं" और "कोड सही ढंग से काम करता है" के बीच की खाई को पाटता है। यह विशेष रूप से उपयोगी है:
\n\n- \n
- डेटा ट्रांसफॉर्मेशन फंक्शन (map, filter, reduce) के लिए \n
- पार्सर और वैलिडेटर के लिए \n
- गैर-तुच्छ तर्क वाले एल्गोरिदम के लिए \n
- सीमा मानों के साथ काम करने वाले फंक्शन के लिए \n
fast-check लाइब्रेरी: त्वरित शुरुआत
\n\nप्रोजेक्ट में fast-check इंस्टॉल करें:
\nnpm install --save-dev fast-check\n\n\nमूल सिंटैक्स:
\nimport fc from 'fast-check';\n\ndescribe('reverse फंक्शन के गुण', () => {\n it('reverse(reverse(arr)) === arr', () => {\n fc.assert(\n fc.property(fc.array(fc.anything()), (arr) => {\n expect(reverse(reverse(arr))).toEqual(arr);\n })\n );\n });\n});\n\n\nयहाँ fc.array(fc.anything()) — मनमाने ऐरे का जनरेटर है। आप जनरेटर को जोड़ सकते हैं:
- \n
fc.integer()— पूर्णांक \n fc.string()— स्ट्रिंग्स \n fc.record({ name: fc.string(), age: fc.integer({ min: 0, max: 120 }) })— ऑब्जेक्ट \n fc.oneof(...)— कई जनरेटर से यादृच्छिक चयन \n
किन गुणों की जाँच करें? 5 व्यावहारिक उदाहरण
\n\n1. इनवेरिएंस (प्रतिवर्तीता)
\nकोई भी ऑपरेशन जिसका उल्टा है, प्रतिवर्ती होना चाहिए:
\nit('JSON का सीरियलाइज़ेशन और डीसीरियलाइज़ेशन', () => {\n fc.assert(\n fc.property(fc.object(), (obj) => {\n const json = JSON.stringify(obj);\n const parsed = JSON.parse(json);\n expect(parsed).toEqual(obj);\n })\n );\n});\n<