2022 की शुरुआत में, मैंने एक चुप्पे फैसले का निर्णय लिया: मैंने Seahawk के जरिये आने वाले ज्यादातर WordPress और Node प्रोजेक्ट्स के लिए यूनिट टेस्ट लिखना बंद कर दिया। जोर-शोर से नहीं। इस बारे में कोई ब्लॉग पोस्ट नहीं। मैं बस... रुक गया। जायज वजह थी, मेरे ख्याल से, हम महीने में 15 से 20 क्लायंट साइट्स शिप कर रहे थे, मेरे पास रोटेशन में तीन और डेवलपर थे, और टेस्ट जो मैं लिख रहा था वो डॉक्यूमेंटेशन की तरह लग रहे थे जो कोई पढ़ता नहीं था। मैनुअल QA ने असली बग्स पकड़े। टेस्ट सिर्फ नाटक थे।
2023 के आखिर में आइए। GitHub Copilot मेरे एडिटर में लगभग आठ महीने तक रहा। मैंने Cursor का भी इस्तेमाल करना शुरू किया साथ में, किसी भी greenfield के लिए। स्पीड वाकई लाजवाब थी। लेकिन कुछ शुरू होने लगा। बग्स ऐसी जगहों पर दिख रहे थे जहां मैंने छुआ तक नहीं था। लॉजिक जो सही दिख रहा था, वो edge cases में गलत था जो मैंने कभी सोचा भी नहीं था। और सबसे बुरी बात, AI को पता ही नहीं था कि वो गलत है। इसने टूटा हुआ कोड उसी आत्मविश्वास से लिखा जैसे यह हमेशा करता है।
तब मैंने टेस्ट्स फिर से उठाया।
---
वह समय जब मैंने टेस्टिंग छोड़ दी (और क्यों यह उस समय समझदारी का काम था)
ईमानदारी से कहूं? एक निश्चित तरह के प्रोजेक्ट के लिए, टेस्ट्स छोड़ना सही फैसला था। अगर आप WordPress में पाँच पेज का ब्रोशर साइट बना रहे हैं, तो contact form plugin के लिए PHPUnit टेस्ट्स लिखना सिर्फ दिखावा है। मैं इस फैसले के पीछे खड़ा हूँ।
Seahawk की रोटी-रोजी की चीज लंबे समय से बिल्कुल वही काम था, ज्यादा वॉल्यूम, रिश्तेदार तौर पर कम मुश्किल, अच्छी तरह परिभाषित स्कोप। एक क्लायंट आपको Figma फाइल देता है, आप इसे बनाते हो, आप QA करते हो, आप शिप करते हो। फीडबैक लूप्स छोटे थे। अगर कुछ टूटता था, तो आपको घंटों के अंदर पता चल जाता था। उस संदर्भ में टेस्ट लिखना डेवलपर के बराबर Post-it नोट को लेमिनेट करना है।
लेकिन मैंने उस सीख को बहुत ज्यादा आक्रामक तरीके से सामान्य बनाया। मैं सभी प्रोजेक्ट्स को ब्रोशर साइट्स की तरह मानने लगा। यहां तक कि कस्टम WooCommerce चेकआउट फ्लो वाली प्रोजेक्ट्स। यहां तक कि fintech डैशबोर्ड जो हमने 2023 की शुरुआत में Frankfurt के एक क्लायंट के लिए बनाया था, पूरी तरह कस्टम REST API, JWT auth, तीन अलग-अलग यूजर परमिशन टियर्स। कोई टेस्ट नहीं। बस "सावधान मैनुअल QA"। वह अहंकार था, और यह हमें काटा।
Frankfurt का प्रोजेक्ट एक permissions bug के साथ ship हुआ जिससे editor-level users, filters के एक specific combination के तहत admin-level data को query कर सकते थे। हमें इसका पता तब चला जब उनकी internal team ने launch के छः हफ्ते बाद एक security review चलाया। शर्मनाक। ठीक करने योग्य। लेकिन यह वह चीज़ है जिसे एक basic integration test ने, pull request raise करने से भी पहले, flag कर दिया होता।
---
AI Coding Tools ने Actually क्या बदला
यहाँ वह चीज़ है जो ज़्यादातर लोग miss करते हैं जब वह Copilot या Cursor या इस महीने का कोई hot model के बारे में बात करते हैं: कोड सही दिखता है। यही तो समस्या है।
जब कोई junior developer buggy code लिखता है, तो अक्सर आप उसमें uncertainty देख सकते हैं। अजीब variable names, एक comment जो कहता है // not sure about this, एक function जो साफ़ तौर पर दो बार copy-paste किया गया है। कोड अपनी अपनी fragility को broadcast करता है। AI code ऐसा नहीं करता। यह stylistically consistent है, well-named है, और एक तरीके से structure किया गया है जो intentional दिखता है। Confidence पूरी तरह से cosmetic है।
Stanford के Human-Computer Interaction group के अध्ययन ने flag किया है कि AI assistants का use करने वाले developers, पहली बार में generated code पर over-trust करने की trend रखते हैं। यह मेरे अपने अनुभव के साथ align करता है। मैं एक 40-line function देखता जो Copilot ने लिखा था, सोचता "हाँ, यही वह है जो मैं लिखता," और आगे बढ़ जाता। कभी-कभी यह ठीक था। कभी-कभी इसने silently गलतफहमी की कि मुझे actually क्या चाहिए।
specific failure mode जो मैं बार-बार hit कर रहा था: edge cases के around conditional logic जिसकी anticipate करने का AI को कोई कारण नहीं था। यह एक ऐसा function लिखता जो happy path को perfectly handle करता और फिर quietly null inputs, empty arrays, या non-standard date formats पर fail करता। ऐसी चीज़ें जिन्हें मैं तीस सेकंड में सोच लेता अगर मैंने code ख़ुद लिखा होता, क्योंकि मैं type करते हुए सोच रहा होता।
स्पीड ट्रैप
यहाँ एक असली प्रोडक्टिविटी ट्रैप है। AI आपको तेज़ बनाता है। तेज़ होना अच्छा लगता है। आप तेज़ी से शिप करने लगते हैं और कम सावधानी से रिव्यू करते हैं क्योंकि वेलोसिटी क्वालिटी का सबूत जैसी लगती है। यह नहीं है। जब आप लैंग्वेज मॉडल को प्रॉम्प्ट कर रहे हों तो स्पीड और करेक्टनेस आपस में जुड़े नहीं हैं।
मैंने सितंबर में एक क्लाइंट प्रोजेक्ट में तकरीबन 40% ज़्यादा फीचर्स डाले, जो मैं AI असिस्टेंस के बिना नहीं कर पाता। लेकिन प्रोजेक्ट में लॉन्च के बाद जितने बग आए, वे पिछले दो साल में मैंने जो कुछ शिप किया था उससे कहीं ज़्यादा थे। कोई कैटास्ट्रॉफिक बग नहीं थे। पर परेशान करने वाले थे। जो क्लाइंट का विश्वास घिसाते हैं।
---
टेस्ट अब अलग तरीके से काम करते हैं (AI लूप में होने के साथ)
जब मैं टेस्टिंग की तरफ वापस आया, तो पुरानी वर्कफ्लो की तरफ वापस नहीं आया। पहले टेस्ट लिखना, फिर इमप्लीमेंटेशन, फिर AI-असिस्टेड कोड रिव्यू, यही लूप है जिसमें मैं अब सेटल हो गया हूं।
दिलचस्प बात यह है कि AI असल में टेस्ट लिखने में बहुत अच्छा है, जिस तरीके से वह हमेशा एप्लिकेशन लॉजिक लिखने में अच्छा नहीं है। Copilot को एक अच्छी तरीके से डिफाइन किया हुआ फंक्शन सिग्नेचर दो और उससे टेस्ट सूट जेनरेट करने के लिए कहो, और यह एज-केस कवरेज निकालेगा जो मुझे मैन्युअली लिखने में बीस मिनट लगते। यह अनहैप्पी पाथ्स अच्छे से कल्पना करता है जब टास्क विशेष रूप से "यह कैसे टूट सकता है इसके तरीके खोजो" हो।
तो मैंने चीज़ को उलट दिया है। मैं टेस्ट स्पेक लिखता हूँ। AI टेस्ट केसेज़ भरता है। फिर AI इंप्लिमेंटेशन लिखता है। फिर मैं इंप्लिमेंटेशन को इन टेस्ट्स के लेंस से पढ़ता हूँ, बस कोड को ठंडे दिमाग से पढ़ने की जगह।
यह शुद्ध वाइब-कोडिंग से धीमा है। पर पुरानी सब कुछ मैन्युअली लिखना-टेस्ट्स भी शामिल-वर्कफ़्लो से तेज़ है। और यह Frankfurt के बाद से शून्य परमिशन्स बग्स शिप किया है।
जो टूल्स मैं असल में यूज़ कर रहा हूँ
- Vitest किसी भी JavaScript या TypeScript के लिए। पिछले साल मेरे लिए Jest की पूरी तरह जगह ले ली, कॉन्फिग ज्यादा समझदारीभरा है और watch mode तेज है।
- WordPress और custom PHP work के लिए अभी भी PHPUnit। इसकी जगह कोई नहीं ले सका है।
- Cursor का "test this function" शॉर्टकट, सच में एडिटर में मैंने जो सिंगल फीचर इस्तेमाल किए हैं उनमें से सबसे ज्यादा मददगार।
- CI के लिए GitHub Actions। हर push पर main को tests चलते हैं। ज़्यादातर projects पर करीब 90 सेकंड लगते हैं।
---
Tests के खिलाफ दलील (Steel-Manned)
मैं इस position को fair hearing देना चाहता हूँ क्योंकि मैंने लगभग दो साल इसे माना था।
असली बहस यह नहीं है कि "टेस्ट बेकार हैं।" यह है कि "टेस्ट की कीमत होती है और कई प्रोजेक्ट्स उस कीमत को जायज नहीं ठहराते।" टेस्ट सूट लिखना और मेंटेन करना समय लेता है। एक छोटी उम्र वाली प्रोजेक्ट के साथ, एक कैंपेन माइक्रोसाइट, एक मार्केटिंग लैंडिंग पेज, एक हैकाथॉन प्रोटोटाइप, उस समय निवेश का जीरो रिटर्न है। प्रोजेक्ट मर जाएगी इससे पहले कि टेस्ट आपको कुछ बचाएं।
और एक और सूक्ष्म बात है: बुरे tests कोई tests नहीं होने से ज़्यादा बुरे हैं। एक test suite जो इसलिए pass होता है क्योंकि tests tautological हैं (आप basically यह test कर रहे हैं कि आपका function वह return करता है जो आपने उसे return करने को कहा था) आपको false confidence देता है। मैंने agencies में ऐसा देखा है। Developers ऐसे tests लिख रहे हैं जो हमेशा pass होते हैं क्योंकि किसी ने challenge नहीं किया कि वो actually क्या verify कर रहे हैं।
Martin Fowler ने इस बारे में अच्छा लिखा है, कवरेज परसेंटेज टेस्ट क्वालिटी का माप नहीं हैं। एक 90% कवरेज नंबर पूरी तरह खोखले सूट को छुपा सकता है।
तो: सब कुछ परीक्षण न करें। परीक्षण इसलिए न करें कि यह पेशेवर लगता है। परीक्षण इसलिए करें क्योंकि आपने ऐसा तर्क पहचाना है जो भार-सहन करने वाला है और जिसे तोड़ना महंगा पड़ेगा।
---
मैं अब क्या परीक्षण करता हूँ (और क्या नहीं)
यह वह वास्तविक निर्णय है जिस पर मैं पिछले आठ या नौ महीनों के बाद पहुँचा हूँ:
मैं परीक्षण करता हूँ:
- कोई भी फ़ंक्शन जो पैसे, अनुमतियों या डेटा ट्रांसफॉर्मेशन को संभालता है
- कोई भी API endpoint जो सीधी CRUD पास-थ्रू नहीं है
- कस्टम बिज़नेस लॉजिक जहाँ क्लाइंट ने लिखित रूप में सटीक व्यवहार निर्दिष्ट किया हो
- कोई भी चीज़ जो AI ने लिखी और जिसे मैंने पूरी तरह लाइन-दर-लाइन नहीं पढ़ा
मैं परीक्षण नहीं करता:
- UI rendering (स्नैपशॉट टेस्ट ने मुझे नौ सालों में एक बार भी नहीं बचाया। एक बार भी नहीं।)
- Third-party API wrappers जहाँ external behaviour मेरे नियंत्रण से बाहर है
- One-off scripts जो एक बार चलती हैं और फिर delete हो जाती हैं
- Standard WordPress hooks जब तक वे कुछ असामान्य न कर रहे हों
बस यही है। कोई बड़ा philosophy नहीं। बस एक list उन जगहों के आधार पर जहाँ मुझे नुकसान हुआ है।
---
The Workflow That Actually Works For Me
चूंकि कुछ लोगों ने Slack communities में मुझसे पूछा है जहाँ मैं हूँ, यहाँ असल sequence है:
- फ़ाइल के शीर्ष पर एक संक्षिप्त spec comment लिखें, जिसमें बताएं कि यह मॉड्यूल क्या करता है, क्या नहीं करता है, और कौन से edge cases आप पहले से जानते हैं।
- कोई भी implementation लिखने से पहले Cursor को उस comment से test cases generate करने के लिए कहें।
- उन टेस्ट केसों को देखें। बेकार वालों को डिलीट करें। जो AI ने मिस किए हों, वो add करें।
- Copilot या Cursor को implementation लिखने दें।
- टेस्ट चलाएं। वो fail होंगे। Implementation को ठीक करें (टेस्ट को नहीं)।
- Push करने से पहले diff को पढ़ें, AI-सहायक कोड को भी एक इंसान से जांचना पड़ता है।
Step 6 non-negotiable है। पिछले चार महीने में मैंने तीन genuinely खराब bugs को सिर्फ diff को धीरे-धीरे पढ़कर push करने से पहले पकड़ा है। कुछ clever नहीं। बस पढ़ना है।
Kent Beck का मूल TDD फ्रेमिंग कभी भी 100% coverage या perfect methodology के बारे में नहीं था। यह एक feedback loop तेजी से बनाने के बारे में था ताकि गलतियों को पकड़ा जा सके इससे पहले कि वे बढ़ जाएं। यह विचार, तेजी से feedback loops, 2003 की तुलना में अब कहीं ज्यादा प्रासंगिक है। क्योंकि AI किसी भी developer से जिसे मैंने नियुक्त किया है, तेजी से गलतियां करता है।
---
FAQ
क्या यह आपकी delivery speed को slow कर देता है?
जटिल projects पर लगभग 10 से 15% तक। सरल projects पर, शायद कुछ भी नहीं, AI tests इतनी जल्दी generate करता है कि overhead minimal है। Projects के लिए जहां एक bug को launch के बाद ठीक करने में असली पैसे खर्च होंगे (और ज्यादातर real-money projects इसमें आते हैं), वह 15% सौ बार लायक है।
TypeScript के बारे में क्या? क्या strong typing बहुत सारे tests की जगह नहीं ले लेता?
आंशिक रूप से। TypeScript compile time पर errors की एक पूरी श्रेणी को पकड़ता है जिसके लिए आपको पहले tests की जरूरत होती थी। लेकिन types business logic को test नहीं करते। वे verify नहीं करते कि आपका discount calculation function wholesale customers के लिए सही rules apply कर रहा है। वह अभी भी आपके ऊपर है।
क्या junior developers को AI coding tools का उपयोग करना चाहिए अगर वे tests नहीं लिख रहे हैं?
नहीं। Strong opinion। एक junior developer जो tests के बिना Copilot का उपयोग कर रहा है वह basically एक plane को autopilot पर fly कर रहा है यह समझे बिना कि autopilot कैसे काम करता है या manually कैसे land करते हैं। AI senior-level दिखने वाला code produce करेगा, junior को पता नहीं चलेगा कि किन हिस्सों पर संदेह करना है, और आपको eventually एक production incident मिलेगा। Tests कम से कम उन्हें output verify करने का एक mechanism देते हैं जो वे accept कर रहे हैं।
आप testing को पहले जगह बंद क्यों किए, सच बताइए?
Burnout, आंशिक रूप से। और एक अवधि जहां हर project genuinely सरल था और tests genuinely अपना मूल्य नहीं दे रहे थे। गलती यह थी कि यह notice नहीं किया कि project की complexity कब बदलती है और तदनुसार adjust नहीं किया। असली सीख यह नहीं है "हमेशा test करो" या "कभी test मत करो" बल्कि यह जानना कि एक दिया गया project किस category में आता है।
---
Tests लिखना पहले protection जैसा महसूस नहीं होता था। यह paperwork जैसा लगता था। AI ने यह बदल दिया। इसलिए नहीं कि AI बुरा है, यह मुझे meaningfully तेजी से बनाता है, बल्कि इसलिए कि इसने confident, well-formatted, plausible-looking गलतियों का एक नया class introduce किया है जिसे मैं code को पढ़ने के तरीके से नहीं पकड़ सकता। Tests AI के लिए नहीं हैं। ये मेरे लिए हैं। एक forcing function ताकि मैं सोचूं कि मुझे असली code में क्या चाहिए, इससे पहले कि मैं जो कुछ भी model देता है उसे accept करूं।
मुझे चाहिए था कि मैं इसे दो साल पहले इसी तरह frame करता।
संबंधित पढ़ना: मैं एक संस्थापक के रूप में Claude Code का दैनिक उपयोग कैसे करता हूँ जो अभी भी Ships करता है, tools, और SEO।
