कोड लिखना इसके लिए टेस्ट लिखने की तुलना में बहुत आसान लगता है, और क्या उस एक-लाइन मेथड को वास्तव में टेस्ट करने की आवश्यकता है, वैसे भी? ये इतना तुच्छ है! आपके द्वारा जोड़े गए कोई भी टेस्ट विकास समय को दोगुना या तिगुना कर देंगे, और अगली बार जब आप कोड बदलेंगे, तो आपको टेस्ट भी बदलना होगा। ये बर्बादी की तरह लगता है, खासकर जब आपके अनुमान पर केवल थोड़ा सा समय बचा हो।
लेकिन जल्द ही, आपका कोड केवल 20% टेस्ट्स द्वारा कवर होता है, और आपके कोड में किया गया कोई भी बदलाव बिना पूरी चीज़ को गिराए ताश के पत्तों के घर की मध्य परत को बदलने की तरह लगता है। कहीं न कहीं, कुछ गलत हो गया और भले ही आपके द्वारा लिए गए निर्णय उस समय सही लगते थे, फिर भी आप एक पूरी तरह से अनरखरखाव योग्य कोडबेस के साथ समाप्त हुए।
आप कैसे यहां पहुंचे? आप चाहते थे कि आपके टेस्ट एक सेफ्टी नेट प्रदान करें और आपको आत्मविश्वास से रिफैक्टर करने की अनुमति दें। उन्हें आपके कोड को बेहतर बनाने में मदद करनी चाहिए थी! इसके बजाय, आप उस कोड पर कम टेस्ट कवरेज के साथ वापस आए जिसे आप अब नहीं समझते, और आपके पास जो टेस्ट हैं वे किसी तरह इसे अधिक कठिन बना देते हैं कोड बदलना।
ये एक कौशल विफलता नहीं है। ये सर्वश्रेष्ठ डेवलपर्स के साथ होता है। ये एक प्रक्रिया विफलता है। नई फीचर्स लिखने के तरीके में कुछ बदलावों के साथ, आप अपने कोड को अपने टेस्ट्स को धीमा किए बिना सुरक्षित कर सकते हैं। आपके टेस्ट आपके कोड को अधिक समझने योग्य और अधिक लचीला बना सकते हैं। आप अपने कोड को आत्मविश्वास से बदल सकेंगे, ये जानते हुए कि इसके माध्यम से हर पथ टेस्टेड है।
आपको निर्णय नहीं लेना चाहिए
अगर आप अपने कीबोर्ड पर बैठकर यह निर्णय लेने की कोशिश कर रहे हैं कि कोड के एक टुकड़े को टेस्ट करने की आवश्यकता है या नहीं, तो आप पहले से ही गलत रास्ते पर जा रहे हैं। आपको हमेशा "इसे टेस्ट करो!" पर डिफ़ॉल्ट होना चाहिए। भले ही ये टेस्ट करने के लिए बहुत तुच्छ लगे, टेस्ट लिखें।
अगर कोड लिखना तुच्छ है, तो इसे टेस्ट करना आसान होना चाहिए। और जटिल कोड कभी भी उतना तुच्छ नहीं लगेगा जितना इसे अभी लिखने के बाद लगता है। आप कैसे जानते हैं कि ये छह महीने बाद भी उतना ही तुच्छ लगेगा?
लेकिन आप ओवरटेस्ट नहीं चाहते
एक विशाल टेस्ट सूट अपनी समस्या हो सकती है। टेस्ट जो 20 मिनट लेते हैं चलने में, किसी काम के नहीं हैं, क्योंकि आप उन्हें हर समय नहीं चलाएंगे। (आप कहते हैं कि आप चलाएंगे, लेकिन मुझे पता है कि आप नहीं चलाएंगे)। इससे भी बदतर, अगर आपके पास बहुत सारे भंगुर टेस्ट हैं, तो ये रिफैक्टरिंग को पहले से भी अधिक दर्दनाक बना देता है, इसलिए आप इसे नहीं करेंगे। आप उन मेथड्स के साथ समाप्त होंगे जो अधिकांश उपन्यासों से लंबे हैं।
क्या ये मेरे पहले बिंदु का विरोध करता है? जरूरी नहीं। आपके टेस्ट्स को हमेशा आपके कोड के इंटरफेस पर ध्यान केंद्रित करना चाहिए, न कि इसके कार्यान्वयन पर। उदाहरण के लिए:
class Cart
def initialize(item_params)
@line_items = Array(item_params).map {|item| LineItem.new(item[:name], item[:price])}
end
def total
@line_items.sum(&:price)
end
end
वास्तव में ऐसा लगता है कि यहां कोड को Cart क्लास और LineItem क्लास दोनों का टेस्ट करने की आवश्यकता है। लेकिन क्या LineItem क्लास किसी और चीज द्वारा उपयोग की जाती है? अगर ये सिर्फ Cart का एक कार्यान्वयन विवरण है, और बाहरी दुनिया के संपर्क में नहीं है, तो इसे वास्तव में कितने टेस्ट की आवश्यकता है? क्या इसे सिर्फ के माध्यम से टेस्ट नहीं किया जा सकता आपके Cart क्लास?
रिफैक्टरिंग द्वारा निकाली गई क्लासेज को अक्सर अपने स्वयं के टेस्ट सूट की आवश्यकता नहीं होती। वे सिर्फ एक कार्यान्वयन विवरण हैं। ये केवल तब होता है जब वे अपने दम पर उपयोग किए जाते हैं कि उन्हें उन अतिरिक्त टेस्ट्स की आवश्यकता होती है।
एक पब्लिक इंटरफेस के खिलाफ एक शानदार टेस्ट सूट के साथ, आपके पास अपने कार्यान्वयन को अपने सभी टेस्ट्स को रीराइट किए बिना बदलने का लचीलापन होता है। आप इसे औसत टेस्ट सूट को अपने ऑब्जेक्ट के कार्यान्वयन के खिलाफ लिखने की तुलना में बहुत कम प्रयास से कर सकते हैं।
टेस्ट-ड्रिवन डेवलपमेंट के साथ अपनी टेस्ट लागत को एमॉर्टाइज़ करें
पहले खंड में, आपने सीखा कि आपको सब कुछ टेस्ट करना चाहिए। दूसरे खंड में, आपने सीखा कि आपको केवल पब्लिक इंटरफेस टेस्ट करना चाहिए। ये टेस्ट-ड्रिवन डेवलपमेंट है जो इन दो विरोधी लक्ष्यों को एक साथ लाता है।
टेस्ट-ड्रिवन डेवलपमेंट के साथ, आपके टेस्ट इस प्रक्रिया का पालन करके आपके कोड के डिज़ाइन और कार्यान्वयन को चलाते हैं:
- एक फेलिंग टेस्ट लिखें जो मानता है कि आपको जिस कोड की आवश्यकता है वो पहले से ही मौजूद है।
- उस कोड का सबसे सरल कार्यान्वयन लिखें जो टेस्ट पास करता है।
- डुप्लीकेशन हटाने के लिए रिफैक्टर करें (या कोड को अधिक अभिव्यंजक बनाएं)।
- टेस्ट्स को फिर से चलाएं (यह सुनिश्चित करने के लिए कि वे अभी भी पास होते हैं)।
- चरण 1 पर लौटें।
इन चरणों का पालन करके, आप सब कुछ टेस्ट करेंगे (चूंकि कोई कोड फेलिंग टेस्ट के बिना नहीं लिखा जाना चाहिए), जबकि केवल पब्लिक इंटरफेस टेस्ट करेंगे (चूंकि आप रिफैक्टरिंग के तुरंत बाद नए टेस्ट नहीं लिखते)।
ये कभी भी बिल्कुल इतना आसान नहीं होता। लेकिन फिर भी सबसे जटिल कोड को टेस्ट-ड्राइव करने के तरीके हैं।
TDD के कुछ साइड बेनिफिट्स हैं:
- आप अपने आप को एक अधिक लचीले, टेस्टेड ऑब्जेक्ट मॉडल के साथ पाएंगे (ये यकीनन मुख्य लाभ है)।
- आपका सिस्टम परिभाषा के अनुसार टेस्टेबल है, जिससे भविष्य के टेस्ट लिखना कम खर्चीला होता है।
- आप अपनी टेस्टिंग लागत को विकास प्रक्रिया में विभाजित करते हैं, जिससे आपके अनुमान अधिक सटीक होते हैं।
- ये आपको फ्लो में रखता है, क्योंकि आपको कभी यह तय नहीं करना पड़ता कि आगे क्या करना है।
तो मैं कैसे शुरू करूं?
शुरू करना कठिन हिस्सा है! एक बार जब आप टेस्ट-ड्रिवन कोड लिखने की लय में आ जाते हैं, तो रुकना मुश्किल होता है।
अगली बार जब आप एक नई फीचर पर काम करें, तो ऊपर दिए गए TDD चरणों का पालन करने का प्रयास करें। आप कम से कम संभव काम के साथ 100% के करीब कोड कवरेज के साथ खुद को पाएंगे, आपके पास निर्माण के लिए एक ठोस नींव होगी, और आपको पूरा भरोसा होगा कि जब आपको अगले साल कोड बदलना होगा तो आपका टेस्ट सूट आपकी रक्षा करेगा। या आज बाद में, जब आपकी आवश्यकताएं फिर से बदलें।
जब आप पूरा कर लें, तो मुझे ईमेल भेजें और मुझे बताएं कि ये कैसा रहा।
एक सीधी टेस्टिंग प्रक्रिया का पालन करके, आप सरल निर्णय लेने और बग्स का पीछा करने में कम समय बिता सकते हैं, और अपने ग्राहकों और व्यवसाय की जरूरतों को हल करने वाले कोड लिखने में अधिक समय बिता सकते हैं।