TDD की बड़ी गलतफहमी (2022)
यहाँ test-driven development (TDD) और unit testing की आलोचनात्मक समीक्षा की गई है, जहाँ कई लोग तर्क देते हैं कि implementation details से बहुत कसकर जुड़े tests नाज़ुक suites बनाते हैं, refactoring को कठिन करते हैं, और मेहनत व्यर्थ कर सकते हैं। टिप्पणीकार low-level unit tests की तुलना उच्च-स्तरीय integration और end-to-end tests से करते हैं, यह बहस करते हुए कि सबसे अच्छा cost–benefit कहाँ है, कितनी coverage वास्तव में उपयोगी है, और क्या tests को मुख्यतः user या system boundary से behavior validate करना चाहिए। इसके पीछे methodologies के प्रति dogmatism को लेकर एक व्यापक चिंता है: कुछ लोग TDD को सोच-समझकर लागू करने पर एक शक्तिशाली design aid मानते हैं, जबकि अन्य इसे situational tooling समझते हैं जिसे context, quality goals, और system complexity के आधार पर चुनना चाहिए।
यूनिट टेस्टिंग में “unit” का अर्थ
- लेख का यह दावा कि “unit” मूल रूप से एक अलग-थलग test को संदर्भित करता था, काफ़ी विवादित है।
- कई टिप्पणीकार पहले की परिभाषाएँ उद्धृत करते हैं (जैसे, “small compilable module, ~100 LOC”), जहाँ unit स्पष्ट रूप से परीक्षण के तहत code है, न कि test।
- थ्रेड में सहमति: भाषा का अर्थ धीरे-धीरे बदला है, लेकिन अधिकांश practitioner और ऐतिहासिक दस्तावेज़ unit को code component (function, class, module) के रूप में देखते हैं, हालांकि कुछ लोग “independent test” को एक उपयोगी आधुनिक धारणा मानते हैं।
क्या TDD testing के बारे में है या design के बारे में?
- एक पक्ष: बड़ी गलतफहमी TDD को testing मानना है; यह मुख्यतः एक design practice है जो tests का उपयोग APIs और separation of concerns को आकार देने के लिए करती है।
- विरोधी पक्ष: TDD-as-design को ज़्यादा महत्त्व दिया गया है या यह हानिकारक है; design skill और judgment अधिक मायने रखते हैं, और TDD कमजोर design guidance देता है, खासकर कम अनुभवी devs के लिए।
- कुछ लोग शब्द को बाँटते हैं: Test-Driven Development बनाम Test-Driven Design, और तर्क देते हैं कि इन्हें अक्सर एक-दूसरे में मिला दिया जाता है।
Unit vs integration/E2E tests
- कई लोगों का तर्क है कि उच्च-स्तरीय functional/integration tests बेहतर मूल्य देते हैं:
- user-visible behavior के अधिक निकट।
- refactors के दौरान अधिक स्थिर।
- tests को implementation और mocking की अति-निर्भरता से बचाते हैं।
- अन्य लोग पारंपरिक testing pyramid का बचाव करते हैं: अनेक तेज़, अलग-थलग unit tests edge cases और bugs पकड़ते हैं जिन्हें व्यापक tests छोड़ सकते हैं, खासकर complex algorithms या libraries के लिए।
- सामान्य समझौता:
- pure, complex logic या reusable foundations के लिए unit tests।
- business workflows और HTTP/JSON या UI boundaries के लिए integration/E2E tests.
नाज़ुक tests और refactoring की परेशानी
- बार-बार की शिकायत: “behavior बदले बिना” refactoring करने पर कई low-level tests टूट जाते हैं।
- कारण: tests बहुत white-box हैं, over-mocking है, या अप्रासंगिक आंतरिक विवरणों पर assertions हैं।
- उल्लिखित रणनीतियाँ:
- tests को externally observable behavior पर केंद्रित करें।
- स्वीकार करें कि कुछ शुरुआती, implementation-focused tests को higher-level behavior tests आने के बाद हटाना या evolve करना चाहिए।
- tests को design constraints से अधिक refactoring के लिए safety harness के रूप में उपयोग करें।
Dogmatism, workflow, और metrics
- “red test के बिना कभी code न बदलें” पर बहस: कुछ इसे TDD का मूल मानते हैं, अन्य इसे अनावश्यक ritual मानते हैं, खासकर exploratory work के दौरान।
- cargo-cult TDD, अनिवार्य 100% coverage, और KPI के रूप में coverage (Goodhart’s law) पर व्यापक संदेह।
- कई लोग context पर ज़ोर देते हैं: domain risk, language (dynamic vs strongly typed), non-functional requirements, और team skill test strategy को तय करने चाहिए, न कि कोई एक सार्वभौमिक methodology.