क्या TDD रक्षात्मक प्रोग्रामिंग को बेमानी बनाता है?


104

आज मैंने एक सहकर्मी के साथ एक दिलचस्प चर्चा की।

मैं एक रक्षात्मक प्रोग्रामर हूं। मेरा मानना ​​है कि नियम " एक वर्ग को यह सुनिश्चित करना चाहिए कि उसकी वस्तुओं की एक वैध स्थिति होती है जब कक्षा के बाहर से बातचीत की जाती है " हमेशा इसका पालन किया जाना चाहिए। इस नियम का कारण यह है कि वर्ग को यह नहीं पता होता है कि उसके उपयोगकर्ता कौन हैं और यह अवैध तरीके से बातचीत करने पर उसे असफल होना चाहिए। मेरी राय में यह नियम सभी वर्गों पर लागू होता है।

विशिष्ट स्थिति में जहां आज मेरी चर्चा थी, मैंने कोड लिखा था जो पुष्टि करता है कि मेरे निर्माता के तर्क सही हैं (जैसे एक पूर्णांक पैरामीटर> 0 होना चाहिए) और यदि पूर्व शर्त पूरा नहीं हुआ है, तो एक अपवाद फेंक दिया जाता है। दूसरी ओर मेरे सहयोगी का मानना ​​है कि इस तरह की जाँच निरर्थक है, क्योंकि यूनिट परीक्षणों को कक्षा के किसी भी गलत उपयोग को पकड़ना चाहिए। इसके अतिरिक्त उनका मानना ​​है कि रक्षात्मक प्रोग्रामिंग सत्यापन को भी इकाई परीक्षण किया जाना चाहिए, इसलिए रक्षात्मक प्रोग्रामिंग बहुत काम जोड़ता है और इसलिए टीडीडी के लिए इष्टतम नहीं है।

क्या यह सच है कि टीडीडी रक्षात्मक प्रोग्रामिंग को बदलने में सक्षम है? क्या पैरामीटर सत्यापन (और मुझे उपयोगकर्ता इनपुट का मतलब नहीं है) एक परिणाम के रूप में अनावश्यक है? या दोनों तकनीक एक दूसरे के पूरक हैं?


120
आप अपनी पूरी तरह से यूनिट-परीक्षण की गई लाइब्रेरी को बिना कंस्ट्रक्टर चेक के एक क्लाइंट को उपयोग करने के लिए सौंप देते हैं, और वे वर्ग अनुबंध को तोड़ देते हैं। अब आप उन यूनिट परीक्षणों में क्या अच्छा करते हैं?
रॉबर्ट हार्वे

42
IMO यह दूसरा तरीका है। रक्षात्मक प्रोग्रामिंग, उचित पूर्व और समर्थक स्थितियाँ, और एक समृद्ध प्रकार की प्रणाली परीक्षण को बेमानी बनाती है।
बाग़ का

37
क्या मैं एक उत्तर पोस्ट कर सकता हूं जो कहता है कि "अच्छा दुःख?" रक्षात्मक प्रोग्रामिंग रनटाइम पर सिस्टम की सुरक्षा करता है। परीक्षण सभी संभावित रनटाइम स्थितियों के लिए जाँच करते हैं, जो परीक्षक के बारे में सोच सकते हैं, जिसमें अवैध तर्क भी शामिल हैं, जो निर्माणकर्ताओं और अन्य तरीकों को पारित किए गए हैं। परीक्षण, यदि पूर्ण हो, तो पुष्टि करेगा कि रनटाइम व्यवहार अपेक्षित होगा, जिसमें उपयुक्त अपवाद फेंके जा रहे हैं या शामिल हैं। अमान्य तर्क पारित होने पर अन्य जानबूझकर व्यवहार हो रहा है। लेकिन परीक्षण रनटाइम पर सिस्टम की सुरक्षा के लिए एक कठिन काम नहीं करते हैं।
क्रेग

16
"यूनिट परीक्षणों को कक्षा के किसी भी गलत उपयोग को पकड़ना चाहिए" - उह, कैसे? यूनिट परीक्षण आपको सही तर्क दिए गए व्यवहार को दिखाएगा, और जब गलत तर्क दिए जाएंगे; वे आपको वह सारे तर्क नहीं दिखा सकते जो कभी दिए जाएंगे।
OJFord

34
मुझे नहीं लगता कि मैंने इस बात का बेहतर उदाहरण देखा है कि सॉफ्टवेयर विकास के बारे में हठधर्मी सोच हानिकारक निष्कर्ष कैसे पहुंचा सकती है।
हेडन

जवाबों:


196

क्या बकवास है। TDD परीक्षणों को पास करने के लिए कोड बनाता है और सभी कोड को इसके चारों ओर कुछ परीक्षण करने के लिए मजबूर करता है। यह आपके उपभोक्ताओं को गलत तरीके से बुलाए गए कोड से नहीं रोकता है, और न ही यह जादुई रूप से प्रोग्रामर को परीक्षण के मामलों को रोकने से रोकता है।

कोई भी कार्यप्रणाली उपयोगकर्ताओं को कोड का सही उपयोग करने के लिए बाध्य नहीं कर सकती है।

इस बात पर थोड़ा तर्क दिया जाता है कि यदि आपने पूरी तरह से टीडीडी किया है तो आप इसे लागू करने से पहले एक परीक्षण मामले में अपने 0 को पकड़ लेंगे, और इसे संबोधित करते हुए - शायद आप चेक को जोड़कर। लेकिन अगर आपने टीडीडी किया, तो आपकी आवश्यकता (कंस्ट्रक्टर में> 0) सबसे पहले एक टेस्टकेस के रूप में दिखाई देगी जो विफल हो जाती है। इस प्रकार आप अपना चेक जोड़ने के बाद आपको टेस्ट दे रहे हैं।

कुछ रक्षात्मक स्थितियों का परीक्षण करना भी उचित है (आपने तर्क जोड़ा, आप इतनी आसानी से परीक्षण योग्य कुछ परीक्षण क्यों नहीं करना चाहेंगे?)। मुझे यकीन नहीं है कि आप इससे सहमत नहीं हैं।

या दोनों तकनीक एक दूसरे के पूरक हैं?

टीडीडी परीक्षणों का विकास करेगा। पैरामीटर सत्यापन लागू करने से वे पास हो जाएंगे।


7
मैं इस विश्वास से असहमत नहीं हूं कि पूर्व-मान्यता सत्यापन का परीक्षण किया जाना चाहिए, लेकिन मैं अपने सहयोगी की राय से असहमत हूं कि पूर्व-मान्यता सत्यापन का परीक्षण करने की आवश्यकता के कारण जो अतिरिक्त काम होता है, वह तर्क है कि पहले से मान्यता सत्यापन नहीं बनाया जाना चाहिए। जगह। मैंने अपनी पोस्ट को स्पष्ट करने के लिए संपादित किया है।
user2180613

20
@ user2180613 एक परीक्षण बनाएं जो परीक्षण करता है कि पूर्व शर्त की विफलता को उचित रूप से नियंत्रित किया जाता है: अब चेक को जोड़ना "अतिरिक्त" काम नहीं है, यह काम है जिसे परीक्षण को हरा बनाने के लिए टीडीडी द्वारा आवश्यक है। यदि आपके सहकर्मी की राय है कि आपको परीक्षण करना चाहिए, तो इसे विफल मानें, और फिर केवल और फिर पूर्व शर्त जांच को लागू करें, फिर उसके पास TDD-purist दृष्टिकोण से एक बिंदु हो सकता है। यदि वह चेक को पूरी तरह से अनदेखा करने के लिए कह रहा है, तो वह मूर्खतापूर्ण है। TDD में ऐसा कुछ भी नहीं है जो कहता है कि आप संभावित विफलता मोड के लिए परीक्षण लिखने में सक्रिय नहीं हो सकते।
RM

4
@RM आप पूर्व-भुगतान जांच का परीक्षण करने के लिए परीक्षण नहीं लिख रहे हैं। आप बुलाए गए कोड के अपेक्षित सही व्यवहार का परीक्षण करने के लिए एक परीक्षण लिख रहे हैं। प्रीकॉन्डिशन चेक, परीक्षण के दृष्टिकोण से, एक अपारदर्शी कार्यान्वयन विवरण है जो सही व्यवहार सुनिश्चित करता है। यदि आप कॉल कोड में सही स्थिति को सुनिश्चित करने के लिए एक बेहतर तरीका सोचते हैं, तो इसे पारंपरिक पूर्व शर्त चेक का उपयोग करने के बजाय इस तरह से करें। परीक्षण किया जाए या नहीं आप सफल रहे थे बाहर उठाना पड़ेगा, और अभी भी पता है या परवाह नहीं करेंगे कैसे आप ऐसा किया।
क्रेग

@ user2180613 यह कुछ भयानक औचित्य है: डी यदि सॉफ्टवेयर लिखने में आपका लक्ष्य है, तो आप लेखक और चलाने के लिए आवश्यक परीक्षणों की संख्या कम कर सकते हैं, न ही कोई सॉफ्टवेयर लिखें - शून्य परीक्षण!
गुस्सोर

3
इस उत्तर के अंतिम वाक्य में यह नाखून है।
राबर्ट ग्रांट

32

रक्षात्मक प्रोग्रामिंग और यूनिट परीक्षण त्रुटियों को पकड़ने के दो अलग-अलग तरीके हैं और प्रत्येक में अलग-अलग ताकत हैं। त्रुटियों का पता लगाने के केवल एक तरीके का उपयोग करने से आपकी त्रुटि का पता लगाने वाली प्रणाली नाजुक हो जाती है। दोनों का उपयोग उन त्रुटियों को पकड़ लेगा जो एक या दूसरे से चूक गए थे, यहां तक ​​कि कोड में भी जो सार्वजनिक रूप से एपीआई का सामना नहीं कर रहा है; उदाहरण के लिए, कोई व्यक्ति सार्वजनिक API में पारित अमान्य डेटा के लिए एक इकाई परीक्षण जोड़ना भूल सकता है। उपयुक्त स्थानों पर सब कुछ जांचने का मतलब है कि त्रुटि को पकड़ने की अधिक संभावना।

सूचना सुरक्षा में, इसे डिफेंस इन डेप्थ कहा जाता है। रक्षा की कई परतें होने से यह सुनिश्चित होता है कि यदि कोई विफल रहता है, तो उसे पकड़ने के लिए अभी भी अन्य हैं।

आपका सहकर्मी एक बात के बारे में सही है: आपको अपनी मान्यताओं का परीक्षण करना चाहिए , लेकिन यह "अनावश्यक काम" नहीं है। यह किसी भी अन्य कोड का परीक्षण करने के समान है, आप यह सुनिश्चित करना चाहते हैं कि सभी usages, यहां तक ​​कि अमान्य भी, एक अपेक्षित परिणाम है।


क्या यह कहना सही है कि पैरामीटर सत्यापन पूर्व शर्त सत्यापन का एक रूप है और यूनिट परीक्षण पोस्टकॉन्डिशन सत्यापन हैं, यही कारण है कि वे एक दूसरे के पूरक हैं?
user2180613

1
"यह किसी भी अन्य कोड का परीक्षण करने के समान है, आप यह सुनिश्चित करना चाहते हैं कि सभी usages, यहां तक ​​कि अमान्य भी, एक अपेक्षित परिणाम है।" इस। किसी भी कोड को कभी नहीं गुजरना चाहिए जब उसके पास से इनपुट को संभालने के लिए डिज़ाइन नहीं किया गया था। यह "विफल तेज़" सिद्धांत का उल्लंघन करता है, और यह एक बुरे सपने को डीबग कर सकता है।
jpmc26

@ user2180613 - वास्तव में नहीं, लेकिन अधिक इकाई परीक्षण उन असफल स्थितियों के लिए जांच करते हैं जो डेवलपर अपेक्षा कर रहा है, जबकि रक्षात्मक प्रोग्रामिंग तकनीक उन स्थितियों की जांच करती है जो डेवलपर अपेक्षा नहीं कर रहा है। यूनिट परीक्षण का उपयोग पूर्व-मान्यताओं को मान्य करने के लिए किया जा सकता है (पूर्व-स्थिति की जाँच करने वाले कॉलर को इंजेक्ट की गई मॉक ऑब्जेक्ट का उपयोग करके)।
पेरिआटा ब्रीटाटा

1
@ jpmc26 हाँ, विफलता है परीक्षा के लिए "की उम्मीद परिणाम"। आप यह दिखाने के लिए परीक्षण करते हैं कि यह कुछ अपरिभाषित (अप्रत्याशित) व्यवहार को चुपचाप प्रदर्शित करने के बजाय विफल रहता है।
KRyan

6
TDD आपके स्वयं के कोड में त्रुटियों को पकड़ता है, रक्षात्मक प्रोग्रामिंग अन्य लोगों के कोड में त्रुटियों को पकड़ता है। TDD इस प्रकार यह सुनिश्चित करने में मदद कर सकता है कि आप पर्याप्त रक्षात्मक हैं :)
5

30

टीडीडी बिल्कुल रक्षात्मक प्रोग्रामिंग को प्रतिस्थापित नहीं करता है। इसके बजाय, आप यह सुनिश्चित करने के लिए टीडीडी का उपयोग कर सकते हैं कि सभी बचाव जगह पर हैं और उम्मीद के मुताबिक काम कर रहे हैं।

टीडीडी में, आपको पहले परीक्षण लिखे बिना कोड लिखने के लिए नहीं माना जाता है - धार्मिक रूप से लाल-हरे-रिफ्लेक्टर चक्र का पालन करें। इसका मतलब है कि यदि आप सत्यापन जोड़ना चाहते हैं, तो पहले एक परीक्षण लिखें जो इस सत्यापन की आवश्यकता है। नकारात्मक संख्याओं और शून्य के साथ प्रश्न में विधि को कॉल करें, और इसे अपवाद फेंकने की अपेक्षा करें।

इसके अलावा, "रिफ्लेक्टर" कदम मत भूलना। जबकि TDD परीक्षण संचालित है , इसका मतलब केवल परीक्षण नहीं है । आपको अभी भी उचित डिज़ाइन लागू करना चाहिए, और समझदार कोड लिखना चाहिए। रक्षात्मक कोड लिखना समझदारी वाला कोड है, क्योंकि यह अपेक्षाओं को अधिक स्पष्ट करता है और आपका कोड समग्र रूप से अधिक मजबूत - संभावित त्रुटियों को जल्दी से मिटाकर उन्हें डीबग करना आसान बनाता है।

लेकिन क्या हम त्रुटियों का पता लगाने के लिए परीक्षणों का उपयोग करने वाले नहीं हैं? दावे और परीक्षण पूरक हैं। एक अच्छी परीक्षा रणनीति यह सुनिश्चित करने के लिए विभिन्न दृष्टिकोणों को मिलाएगी कि सॉफ्टवेयर मजबूत है। केवल इकाई परीक्षण या केवल एकीकरण परीक्षण या कोड में केवल दावे सभी असंतोषजनक हैं, आपको स्वीकार्य प्रयास के साथ अपने सॉफ़्टवेयर में पर्याप्त डिग्री तक पहुंचने के लिए एक अच्छे संयोजन की आवश्यकता है।

फिर आपके सहकर्मी की एक बहुत बड़ी वैचारिक गलतफहमी है: इकाई परीक्षण कभी भी आपकी कक्षा के उपयोग का परीक्षण नहीं कर सकते हैं , केवल यह कि वर्ग ही अलगाव में अपेक्षित रूप से काम करता है। आप यह जांचने के लिए एकीकरण परीक्षणों का उपयोग करेंगे कि विभिन्न घटक कार्यों के बीच की बातचीत, लेकिन संभावित परीक्षण मामलों के दहनशील विस्फोट से सब कुछ परीक्षण करना असंभव हो जाता है। इसलिए एकीकरण परीक्षणों से खुद को कुछ महत्वपूर्ण मामलों तक सीमित रखना चाहिए। अधिक विस्तृत परीक्षण जो कि किनारे के मामलों को भी कवर करते हैं और त्रुटि के मामले यूनिट परीक्षणों के लिए अधिक उपयुक्त होते हैं।


16

रक्षात्मक प्रोग्रामिंग का समर्थन करने और सुनिश्चित करने के लिए टेस्ट हैं

रक्षात्मक प्रोग्रामिंग रनटाइम पर सिस्टम की अखंडता की रक्षा करता है।

परीक्षण (ज्यादातर स्थिर) नैदानिक ​​उपकरण हैं। रनटाइम में, आपके परीक्षण कहीं नहीं हैं। वे एक उच्च ईंट की दीवार या एक चट्टान गुंबद को लगाने के लिए उपयोग किए जाने वाले मचान की तरह हैं। आप संरचना से महत्वपूर्ण हिस्सों को नहीं छोड़ते हैं क्योंकि आपके पास निर्माण के दौरान इसे रखने के लिए एक मचान है। आपके पास सभी महत्वपूर्ण टुकड़ों को रखने की सुविधा के लिए निर्माण के दौरान इसे रखने के लिए एक मचान है।

संपादित करें: एक सादृश्य

कोड में टिप्पणियों के लिए एक सादृश्य के बारे में क्या?

टिप्पणियों का अपना उद्देश्य है, लेकिन निरर्थक या हानिकारक भी हो सकता है। उदाहरण के लिए, यदि आप कोड के बारे में आंतरिक ज्ञान को टिप्पणियों में रखते हैं , तो कोड को बदल दें, टिप्पणियां सबसे अच्छी और अप्रासंगिक हो जाती हैं।

तो कहते हैं कि आप अपने कोड आधार के बहुत सारे आंतरिक ज्ञान को परीक्षणों में डालते हैं, जैसे कि मेथड एक शून्य नहीं ले सकता है और मेथोडब का तर्क होना चाहिए > 0। फिर कोड बदलता है। नल अभी A के लिए ठीक है, और B मानों को छोटे -10 के रूप में ले सकता है। मौजूदा परीक्षण अब कार्यात्मक रूप से गलत हैं, लेकिन पास करना जारी रखेंगे।

हां, आपको उसी समय परीक्षणों को अपडेट करना चाहिए जब आप कोड को अपडेट करते हैं। जिस समय आप कोड अपडेट करते हैं, उसी समय आपको टिप्पणियां (या हटाना) भी अपडेट होनी चाहिए। लेकिन हम सभी जानते हैं कि ये चीजें हमेशा नहीं होती हैं, और ये गलतियां होती हैं।

परीक्षण प्रणाली के व्यवहार को सत्यापित करते हैं। वह वास्तविक व्यवहार प्रणाली के लिए आंतरिक है, परीक्षणों के लिए आंतरिक नहीं है

क्या गलत होने की सम्भावना है?

परीक्षणों के संबंध में लक्ष्य यह है कि जो कुछ भी गलत हो सकता है, उसके बारे में सोचें, उसके लिए एक परीक्षण लिखें जो सही व्यवहार के लिए जांच करता है, फिर रनटाइम कोड को तैयार करता है ताकि यह सभी परीक्षणों को पास कर सके।

जिसका मतलब है कि रक्षात्मक प्रोग्रामिंग बिंदु है

TDD ड्राइव रक्षात्मक प्रोग्रामिंग, अगर परीक्षण व्यापक हैं।

अधिक परीक्षण, अधिक रक्षात्मक प्रोग्रामिंग ड्राइविंग

जब कीड़े अनिवार्य रूप से पाए जाते हैं, तो बग को प्रकट करने वाली स्थितियों को मॉडल करने के लिए अधिक परीक्षण लिखे जाते हैं। फिर कोड तय किया जाता है, उन परीक्षणों को पास करने के लिए कोड के साथ , और नए परीक्षण टेस्ट सूट में रहते हैं।

परीक्षणों का एक अच्छा सेट एक फ़ंक्शन / विधि के लिए अच्छे और बुरे दोनों तर्क पारित करने जा रहा है, और लगातार परिणामों की अपेक्षा करता है। यह, बदले में, इसका मतलब है कि परीक्षण किया गया घटक पूर्वगामी जांच (रक्षात्मक प्रोग्रामिंग) का उपयोग करने जा रहा है ताकि यह पारित होने वाले तर्कों की पुष्टि कर सके।

आम तौर पर बोल रहा हूँ ...

उदाहरण के लिए, यदि किसी विशेष प्रक्रिया के लिए एक अशक्त तर्क अमान्य है, तो कम से कम एक परीक्षण एक अशक्त पास करने जा रहा है, और यह किसी प्रकार के "अमान्य अशक्त तर्क" अपवाद / त्रुटि की अपेक्षा करने वाला है।

कम से कम एक अन्य परीक्षण एक वैध तर्क पारित करने के लिए जा रहा है , निश्चित रूप से - या एक बड़े सरणी के माध्यम से लूप और umpteen मान्य तर्क पास - और पुष्टि करें कि परिणामी स्थिति उपयुक्त है।

यदि कोई परीक्षण उस अशक्त तर्क को पारित नहीं करता है और अपेक्षित अपवाद के साथ थप्पड़ मारा जाता है (और उस अपवाद को फेंक दिया गया था, क्योंकि कोड ने रक्षात्मक रूप से राज्य को इसे पास कर दिया था), तो शून्य अंत में एक वर्ग की संपत्ति को सौंपा जा सकता है या दफन हो सकता है कुछ प्रकार के संग्रह में जहां यह नहीं होना चाहिए।

यह सिस्टम के कुछ पूरी तरह से अलग हिस्से में अप्रत्याशित व्यवहार का कारण हो सकता है जो कि सॉफ्टवेयर द्वारा शिप किए जाने के बाद कुछ दूर के भौगोलिक स्थान पर कक्षा के उदाहरण के लिए पास हो जाता है । और इस तरह की चीज हम वास्तव में बचने की कोशिश कर रहे हैं, है ना?

यह और भी बुरा हो सकता है। अमान्य स्थिति वाला वर्ग उदाहरण क्रमबद्ध और संग्रहीत किया जा सकता है, केवल तब विफलता का कारण बन सकता है जब इसे बाद में उपयोग के लिए पुनर्गठित किया जाए। Geez, मुझे नहीं पता, शायद यह किसी तरह का एक यांत्रिक नियंत्रण प्रणाली है जो एक शटडाउन के बाद पुनः आरंभ नहीं कर सकता है क्योंकि यह अपने स्वयं के निरंतर कॉन्फ़िगरेशन स्थिति को निष्क्रिय नहीं कर सकता है। या वर्ग उदाहरण को क्रमबद्ध किया जा सकता है और किसी अन्य इकाई द्वारा बनाई गई कुछ पूरी तरह से अलग प्रणाली में पारित किया जा सकता है, और यह प्रणाली दुर्घटनाग्रस्त हो सकती है।

खासकर अगर उस सिस्टम के अन्य प्रोग्रामर ने रक्षात्मक रूप से कोड नहीं किया।


2
यह हास्यास्पद है, डाउनवोट इतनी तेजी से आया है कि अब पूरी तरह से डाउनवॉटर संभवतः पहले पैराग्राफ से परे पढ़ा जा सकता है।
क्रेग

1
:-) मैं सिर्फ पहले पैराग्राफ से परे पढ़े बिना मतदान करता हूँ, इसलिए उम्मीद है कि इसे संतुलित करूंगा ...
SusanW

1
लगता है कम से कम मैं कर सकता था :-) (वास्तव में, मैं सिर्फ यकीन करने के लिए बाकी पढ़ा था । मैला नहीं होना चाहिए - विशेष रूप से इस तरह एक विषय पर!)
SusanW

1
मुझे लगा कि तुम शायद था। :)
क्रेग

रक्षात्मक चेक कोड अनुबंध जैसे उपकरणों के साथ संकलन समय पर किया जा सकता है।
मैथ्यू Whited

9

टीडीडी के बजाय "सॉफ़्टवेयर परीक्षण" के बारे में सामान्य रूप से बात करते हैं, और सामान्य रूप से "रक्षात्मक प्रोग्रामिंग" के बजाय, चलो रक्षात्मक प्रोग्रामिंग करने के मेरे पसंदीदा तरीके के बारे में बात करते हैं, जो कि अभिकथन का उपयोग करके है।


इसलिए, जब से हम सॉफ्टवेयर परीक्षण करते हैं, हमें उत्पादन कोड में मुखर बयान देना छोड़ देना चाहिए, है ना? मुझे उन तरीकों को गिनने दें जिनमें यह गलत है:

  1. दावे वैकल्पिक हैं, इसलिए यदि आप उन्हें पसंद नहीं करते हैं, तो बस अपने सिस्टम को अक्षम अक्षमताओं के साथ चलाएं।

  2. दावे उन चीजों की जांच करते हैं जो परीक्षण नहीं कर सकते (और नहीं।) क्योंकि परीक्षण को आपके सिस्टम का एक ब्लैक-बॉक्स दृश्य माना जाता है, जबकि अभिकथन में एक सफेद-बॉक्स दृश्य होता है। (बेशक, चूंकि वे इसमें रहते हैं।)

  3. दावे एक उत्कृष्ट प्रलेखन उपकरण हैं। कभी भी कोई टिप्पणी नहीं की गई थी, या कभी नहीं होगी, जैसा कि एक ही चीज़ को मुखर करने वाले कोड के एक टुकड़े के रूप में अस्पष्ट है। इसके अलावा, कोड विकसित होते ही प्रलेखन पुराना हो जाता है, और यह किसी भी तरह से संकलक द्वारा प्रवर्तनीय नहीं होता है।

  4. परीक्षण कोड में दावे त्रुटियों को पकड़ सकते हैं। क्या आप कभी ऐसी स्थिति में भागे हैं जहाँ कोई परीक्षण विफल होता है, और आपको नहीं पता कि कौन गलत है - उत्पादन कोड, या परीक्षण?

  5. परीक्षण की तुलना में दावे अधिक प्रासंगिक हो सकते हैं। कार्यात्मक आवश्यकताओं द्वारा निर्धारित किए गए परीक्षणों की जांच होगी, लेकिन कोड को अक्सर कुछ मान्यताओं को बनाना पड़ता है जो कि उससे कहीं अधिक तकनीकी हैं। कार्यात्मक आवश्यकताओं के दस्तावेज लिखने वाले लोग शायद ही कभी शून्य से विभाजन के बारे में सोचते हैं।

  6. अभिकथन में त्रुटियों को इंगित करता है जो केवल मोटे तौर पर संकेत का परीक्षण करता है। इसलिए, आपका परीक्षण कुछ व्यापक प्राथमिकताओं को निर्धारित करता है, कोड के कुछ लंबे टुकड़े को आमंत्रित करता है, परिणामों को इकट्ठा करता है, और पाता है कि वे अपेक्षित नहीं हैं। पर्याप्त समस्या निवारण को देखते हुए आप अंततः वही पाएंगे जहाँ चीजें गलत हुई थीं, लेकिन दावे आम तौर पर पहले मिल जाएंगे।

  7. दावे कार्यक्रम की जटिलता को कम करते हैं। कोड की हर एक पंक्ति जो आप लिखते हैं, कार्यक्रम की जटिलता बढ़ाती है। अभिकथन और final( readonly) कीवर्ड केवल दो निर्माण हैं जो मुझे पता है कि वास्तव में कार्यक्रम की जटिलता को कम करते हैं। वह अनमोल है।

  8. संकलक आपके कोड की बेहतर समझ बनाने में मदद करते हैं। कृपया इसे घर पर आज़माएँ: void foo( Object x ) { assert x != null; if( x == null ) { } }आपके संकलक को यह कहते हुए चेतावनी जारी करनी चाहिए कि स्थिति x == nullहमेशा झूठी है। यह बहुत उपयोगी हो सकता है।

उपरोक्त मेरे ब्लॉग, 2014-09-21 के एक पोस्ट का सारांश था "दावे और परीक्षण"


मुझे लगता है कि मैं ज्यादातर इस जवाब से असहमत हूं। (5) टीडीडी में, परीक्षण सूट विनिर्देश है। आप टेस्ट पास करने वाले सबसे सरल कोड लिखने वाले हैं, इससे अधिक कुछ नहीं। (४) रेड-ग्रीन वर्कफ़्लो यह सुनिश्चित करता है कि परीक्षण तब विफल हो जाता है जब इसे इच्छित कार्यक्षमता मौजूद होने पर पास करना चाहिए। दावे यहाँ बहुत मदद नहीं करते हैं। (3,7) डॉक्यूमेंटेशन डॉक्यूमेंटेशन है, दावे नहीं हैं। लेकिन मान्यताओं को स्पष्ट करने से, कोड अधिक स्व-दस्तावेजीकरण बन जाता है। मैं उन्हें निष्पादन योग्य टिप्पणियों के रूप में सोचता हूं। (2) व्हाइट-बॉक्स परीक्षण एक मान्य परीक्षण रणनीति का हिस्सा हो सकता है।
आमोन

5
"टीडीडी में, परीक्षण सूट विनिर्देश है। आप परीक्षणों को पास करने वाले सबसे सरल कोड को लिखने वाले हैं, और कुछ नहीं।": मुझे नहीं लगता कि यह हमेशा एक अच्छा विचार है: जैसा कि उत्तर में बताया गया है, वहाँ हैं। कोड में अतिरिक्त आंतरिक धारणा जिसे सत्यापित करना चाहते हैं। आंतरिक बग के बारे में क्या जो एक दूसरे को रद्द करते हैं? आपके परीक्षण पास हो जाते हैं लेकिन आपके कोड के अंदर कुछ धारणाएं गलत हैं, जो बाद में कपटी बग पैदा कर सकती हैं।
जियोर्जियो

5

मेरा मानना ​​है कि अधिकांश उत्तर एक महत्वपूर्ण अंतर याद कर रहे हैं: यह इस बात पर निर्भर करता है कि आपके कोड का उपयोग कैसे किया जा रहा है।

क्या आपके द्वारा परीक्षण किए जा रहे एप्लिकेशन के अन्य ग्राहकों द्वारा उपयोग किए जाने वाले प्रश्न में मॉड्यूल है? यदि आप तृतीय-पक्ष द्वारा उपयोग के लिए एक पुस्तकालय या एपीआई प्रदान कर रहे हैं, तो आपके पास यह सुनिश्चित करने का कोई तरीका नहीं है कि वे केवल मान्य इनपुट के साथ आपके कोड को कॉल करें। आपको सभी इनपुट को मान्य करना होगा।

लेकिन यदि प्रश्न में मॉड्यूल केवल आपके द्वारा नियंत्रित कोड द्वारा उपयोग किया जाता है, तो आपके मित्र के पास एक बिंदु हो सकता है। आप यह सत्यापित करने के लिए इकाई परीक्षणों का उपयोग कर सकते हैं कि प्रश्न में मॉड्यूल केवल वैध इनपुट के साथ कहा जाता है। पूर्व-भुगतान चेक को अभी भी एक अच्छा अभ्यास माना जा सकता है, लेकिन यह एक व्यापार-बंद है: मैं आपको वह कोड देता हूं जो ऐसी स्थिति की जांच करता है जिसे आप जानते हैं कि वह कभी उत्पन्न नहीं हो सकती, यह सिर्फ कोड के इरादे को अस्पष्ट करता है।

मैं असहमत हूं कि पूर्व-भुगतान जांच के लिए अधिक यूनिट-परीक्षणों की आवश्यकता होती है। यदि आप तय करते हैं कि आपको अवैध इनपुट के कुछ रूपों का परीक्षण करने की आवश्यकता नहीं है, तो यह नहीं होना चाहिए कि फ़ंक्शन में पूर्व शर्त चेक शामिल हैं या नहीं। याद रखें परीक्षणों को व्यवहार को सत्यापित करना चाहिए, न कि विवरण को लागू करना।


4
यदि प्रक्रिया कहा जाता है , तो इनपुट की वैधता को सत्यापित नहीं करता है (जो कि मूल बहस है) तो आपकी इकाई परीक्षण यह सुनिश्चित नहीं कर सकती है कि विचाराधीन मॉड्यूल केवल वैध इनपुट के साथ कहा जाता है। विशेष रूप से, इसे अमान्य इनपुट के साथ कहा जा सकता है, लेकिन परीक्षण के मामलों में वैसे भी एक सही परिणाम वापस करने के लिए होता है - विभिन्न प्रकार के अपरिभाषित व्यवहार, अतिप्रवाह हैंडलिंग आदि होते हैं, जो अक्षम अनुकूलन के साथ परीक्षण वातावरण में अपेक्षित परिणाम वापस कर सकते हैं लेकिन उत्पादन में असफल।
Peteris

@Peteris: क्या आप C की तरह अपरिभाषित व्यवहार के बारे में सोच रहे हैं? अपरिभाषित व्यवहार को लागू करना, जिसका अलग-अलग वातावरणों में अलग-अलग परिणाम होता है, जाहिर तौर पर यह एक बग है, लेकिन इसे पहले से जांच के कारण रोका नहीं जा सकता। उदाहरण के लिए, आप एक वैध तर्क बिंदुओं की जाँच कैसे करते हैं?
जैक्सबी

3
यह केवल छोटी दुकानों में काम करेगा। एक बार जब आपकी टीम, छह लोगों से परे हो जाती है, तो आपको वैसे भी सत्यापन जांच की आवश्यकता होगी।
रॉबर्ट हार्वे

1
@RobertHarvey: उस स्थिति में सिस्टम को सबसिस्टम में अच्छी तरह से परिभाषित इंटरफेस के साथ विभाजित किया जाना चाहिए, और इनपुट सत्यापन इंटरफ़ेस पर किया जाता है।
जैक्सबी

इस। यह कोड पर निर्भर करता है, क्या यह कोड टीम द्वारा उपयोग किया जाना है? क्या टीम के पास सोर्स कोड है? यदि इसका विशुद्ध रूप से आंतरिक कोड है, तो तर्कों के लिए जाँच करना केवल एक बोझ हो सकता है, उदाहरण के लिए, आप 0 के लिए जाँच करते हैं और फिर अपवाद को फेंकते हैं, और कॉलर फिर कोड में देखता है कि यह वर्ग अपवाद आदि को फेंक सकता है और प्रतीक्षा कर सकता है .. इस मामले में। ऑब्जेक्ट कभी भी 0 प्राप्त नहीं करेगा क्योंकि उन्हें पहले 2 lvls को फ़िल्टर किया गया था। यदि थ्री जी पार्टियों द्वारा उपयोग किया जाने वाला एक पुस्तकालय कोड है तो एक और कहानी है। पूरी दुनिया द्वारा उपयोग किए जाने के लिए कोई भी कोड नहीं लिखा गया है।
अलेक्जेंडर फुलर

3

यह तर्क मुझे चकित करता है, क्योंकि जब मैंने टीडीडी का अभ्यास करना शुरू किया था, तो फॉर्म की मेरी इकाई परीक्षण "वस्तु प्रतिक्रिया करता है <निश्चित तरीका> जब <अवैध इनपुट>" 2 या 3 गुना बढ़ जाता है। मैं सोच रहा हूँ कि आपका सहकर्मी अपने कार्यों को बिना सत्यापन के सफलतापूर्वक कैसे कर सकता है।

विपरित मामला, उस इकाई परीक्षण से पता चलता है कि आप कभी भी खराब आउटपुट उत्पन्न नहीं कर रहे हैं जो अन्य कार्यों के तर्कों को पारित किया जाएगा, यह साबित करना अधिक कठिन है। पहले मामले की तरह, यह पूरी तरह से किनारे के मामलों की कवरेज पर निर्भर करता है, लेकिन आपके पास अतिरिक्त आवश्यकता है कि आपके सभी फ़ंक्शन इनपुट को अन्य कार्यों के आउटपुट से आना चाहिए, जिनके आउटपुट का आपने परीक्षण किया है और न कि, उपयोगकर्ता इनपुट या तीसरे पक्ष के मॉड्यूल।

दूसरे शब्दों में, टीडीडी आपको सत्यापन कोड की आवश्यकता से उतना नहीं रोकता है जितना आप इसे भूलने से रोकने में मदद करते हैं ।


2

मुझे लगता है कि मैं आपके सहयोगी की टिप्पणियों को बाकी के अधिकांश उत्तरों से अलग तरीके से समझाता हूं।

यह मुझे लगता है कि तर्क है:

  • हमारे सभी कोड यूनिट टेस्टेड हैं।
  • आपके घटक का उपयोग करने वाला सभी कोड हमारा कोड है, या नहीं तो किसी और के द्वारा यूनिट का परीक्षण किया गया है (स्पष्ट रूप से कहा नहीं गया है, लेकिन यह वही है जो मैं समझता हूं कि "इकाई परीक्षण कक्षा के किसी भी गलत उपयोग को पकड़ना चाहिए")।
  • इसलिए, आपके फ़ंक्शन के प्रत्येक कॉलर के लिए कहीं एक इकाई परीक्षण होता है जो आपके घटक का मज़ाक उड़ाता है, और यदि कॉलर उस नकली को अमान्य मान देता है, तो परीक्षण विफल हो जाता है।
  • इसलिए, इससे कोई फर्क नहीं पड़ता कि अमान्य मान पास होने पर आपका कार्य क्या करता है, क्योंकि हमारे परीक्षण कहते हैं कि ऐसा नहीं हो सकता।

मेरे लिए, इस तर्क के पास कुछ तर्क हैं, लेकिन हर संभावित स्थिति को कवर करने के लिए यूनिट परीक्षणों पर बहुत अधिक निर्भरता रखता है। सरल तथ्य यह है कि 100% लाइन / शाखा / पथ कवरेज जरूरी नहीं है कि हर मूल्य उस फोनर को पास कर सके, जबकि कॉलर के सभी संभावित राज्यों में 100% कवरेज (जो कहना है, उसके इनपुट के सभी संभावित मान और चर) कम्प्यूटेशनल रूप से अलग है।

इसलिए मैं यह सुनिश्चित करने के लिए कॉल करने वालों को यूनिट-परीक्षण करना पसंद करूंगा कि (अब तक परीक्षण चलते हैं) वे कभी भी खराब मानों में नहीं गुजरते हैं, और इसके अलावा आवश्यकता होती है कि आपका घटक कुछ पहचाने जाने योग्य तरीके से विफल हो जाता है जब एक खराब मूल्य पास हो जाता है। कम से कम जहाँ तक आपकी पसंद की भाषा में बुरे मूल्यों को पहचानना संभव है)। यह डिबगिंग में सहायता करेगा जब समस्याएं एकीकरण परीक्षणों में होती हैं, और इसी तरह आपके वर्ग के किसी भी उपयोगकर्ता को सहायता प्रदान करेगी जो अपनी कोड इकाई को उस निर्भरता से अलग करने में कठोर से कम है।

हालांकि इस बात से अवगत रहें कि यदि आप अपने फ़ंक्शन के व्यवहार का दस्तावेजीकरण और परीक्षण करते हैं, जब एक मान <= 0 में पारित किया जाता है, तो नकारात्मक मान अब अमान्य नहीं हैं (कम से कम, इससे अधिक अमान्य कोई भी तर्क नहीं है throw, क्योंकि उसके बाद से भी एक अपवाद फेंकने के लिए प्रलेखित है!)। कॉल करने वाले उस रक्षात्मक व्यवहार पर भरोसा करने के हकदार हैं। भाषा की अनुमति, यह हो सकता है कि यह किसी भी मामले में सबसे अच्छा परिदृश्य हो - फ़ंक्शन में कोई "अमान्य इनपुट" नहीं है, लेकिन कॉल करने वाले जो अपवाद को फेंकने में फ़ंक्शन को भड़काने की उम्मीद नहीं करते हैं, उन्हें डॉन सुनिश्चित करने के लिए पर्याप्त रूप से यूनिट-परीक्षण किया जाना चाहिए ' टी किसी भी मूल्यों को पारित करें जो इसका कारण बनते हैं।

यह सोचने के बावजूद कि आपका सहकर्मी अधिकांश उत्तरों की तुलना में कुछ हद तक गलत है, मैं उसी निष्कर्ष पर पहुंचता हूं, जो यह है कि दोनों तकनीक एक-दूसरे के पूरक हैं। रक्षात्मक रूप से कार्यक्रम करें, अपनी रक्षात्मक जाँचों का दस्तावेजीकरण करें और उनका परीक्षण करें। यदि आपके कोड के उपयोगकर्ता गलती करते समय उपयोगी त्रुटि संदेशों से लाभ नहीं उठा सकते हैं तो यह केवल "अनावश्यक" है। सिद्धांत रूप में, यदि वे पूरी तरह से आपके साथ इसे एकीकृत करने से पहले अपने सभी कोड का परीक्षण करते हैं, और उनके परीक्षणों में कभी कोई त्रुटि नहीं होती है, तो वे त्रुटि संदेश कभी नहीं देखेंगे। व्यवहार में भी अगर वे टीडीडी और कुल निर्भरता इंजेक्शन कर रहे हैं, तो वे अभी भी विकास के दौरान पता लगा सकते हैं या उनके परीक्षण में कोई चूक हो सकती है। नतीजा यह होता है कि उनका कोड सही होने से पहले वे आपके कोड को कॉल करते हैं!


यह सुनिश्चित करने के लिए कि वे बुरे मूल्यों को पारित नहीं करते हैं, यह सुनिश्चित करने के लिए कॉलर्स के परीक्षण पर जोर देने का व्यवसाय बहुत सारे बास एक प्रकार की निर्भरता के साथ नाजुक कोड को उधार देता है, और चिंताओं का कोई साफ पृथक्करण नहीं है। मुझे नहीं लगता कि मैं उस दृष्टिकोण के पीछे की सोच के परिणामस्वरूप कोड को पसंद करूंगा।
क्रेग

@ क्रेग: इसे इस तरह से देखें, यदि आपने इसकी निर्भरता का मजाक उड़ाते हुए परीक्षण के लिए एक घटक को अलग कर दिया है, तो आप यह क्यों नहीं परखेंगे कि यह केवल उन निर्भरताओं के लिए सही मान देता है? और अगर आप घटक को अलग नहीं कर सकते हैं तो क्या आपने वास्तव में चिंताओं को अलग कर दिया है? मैं रक्षात्मक कोडिंग से असहमत नहीं हूं, लेकिन यदि रक्षात्मक चेक ऐसे साधन हैं जिनके द्वारा आप कॉलिंग कोड की शुद्धता का परीक्षण कर रहे हैं तो यह गड़बड़ है। इसलिए मुझे लगता है कि प्रश्नकर्ता का सहकर्मी सही है कि चेक बेमानी हैं, लेकिन इसे गलत तरीके से न लिखने के कारण के रूप में देखना :-)
स्टीव जेसप

एकमात्र चमकता हुआ छेद जिसे मैं देख रहा हूं कि मैं अभी भी केवल यह परीक्षण कर रहा हूं कि मेरे अपने घटक कैंट उन निर्भरताओं के लिए अमान्य मानों को पारित करें, जिनके बारे में मैं पूरी तरह सहमत हूं, लेकिन यह होना चाहिए कि कितने व्यवसाय प्रबंधक निजी बनाने के लिए कितने निर्णय लेते हैं घटक सार्वजनिक ताकि पार्टनर इसे कॉल कर सकें? यह वास्तव में मुझे डेटाबेस डिजाइन की याद दिला रहा है, और ओआरएम के साथ सभी मौजूदा प्रेम संबंध हैं, जिसके परिणामस्वरूप बहुत सारे (ज्यादातर युवा) लोग घोषणा कर रहे हैं कि डेटाबेस केवल गूंगा नेटवर्क भंडारण हैं और खुद को बाधाओं, विदेशी चाबियों और संग्रहीत प्रक्रियाओं से सुरक्षित नहीं करना चाहिए।
क्रेग

दूसरी बात जो मैं देख रहा हूं, वह यह है कि निश्चित रूप से, यह है कि आप केवल मौकों पर कॉल का परीक्षण कर रहे हैं, वास्तविक निर्भरता के लिए नहीं। यह अंततः उन निर्भरता में कोड है जो विशेष रूप से पारित मूल्य के साथ उचित रूप से काम नहीं कर सकते हैं, न कि कॉलर में कोड। तो निर्भरता को सही काम करने की आवश्यकता है, और यह सुनिश्चित करने के लिए निर्भरता के पर्याप्त स्वतंत्र परीक्षण कवरेज की आवश्यकता है कि यह करता है। याद रखें, हम जिन परीक्षणों के बारे में बात कर रहे हैं, उन्हें "यूनिट" परीक्षण कहा जाता है। प्रत्येक निर्भरता एक इकाई है। :)
क्रेग

1

सार्वजनिक इंटरफेस का दुरुपयोग किया जा सकता है

आपके सहकर्मी का दावा "इकाई परीक्षणों को वर्ग के किसी भी गलत उपयोग को पकड़ना चाहिए" किसी भी इंटरफ़ेस के लिए कड़ाई से गलत है जो निजी नहीं है। यदि किसी सार्वजनिक फ़ंक्शन को पूर्णांक तर्कों के साथ बुलाया जा सकता है, तो यह किसी भी पूर्णांक तर्कों के साथ कहा जा सकता है, और कोड को उचित रूप से व्यवहार करना चाहिए। यदि कोई सार्वजनिक फ़ंक्शन हस्ताक्षर जावा डबल प्रकार को स्वीकार करता है, तो null, NaN, MAX_VALUE, -Inf सभी संभव मान हैं। आपकी इकाई परीक्षण वर्ग के गलत उपयोगों को नहीं पकड़ सकती क्योंकि वे परीक्षण उस कोड का परीक्षण नहीं कर सकते हैं जो इस वर्ग का उपयोग करेगा, क्योंकि वह कोड अभी तक नहीं लिखा गया है, शायद आपके द्वारा नहीं लिखा जा सकता है, और निश्चित रूप से आपकी इकाई परीक्षणों के दायरे से बाहर होगा। ।

दूसरी ओर, यह दृष्टिकोण निजी संपत्तियों के लिए (उम्मीद से बहुत अधिक) निजी संपत्तियों के लिए मान्य हो सकता है - यदि कोई वर्ग यह सुनिश्चित कर सकता है कि कोई तथ्य हमेशा सत्य होता है (जैसे संपत्ति एक्स कभी शून्य नहीं हो सकती है, तो पूर्णांक स्थिति अधिकतम लंबाई से अधिक नहीं होती है , जब फ़ंक्शन A को कहा जाता है, सभी पूर्वापेक्षा डेटा संरचनाएं अच्छी तरह से बनती हैं) तो प्रदर्शन कारणों के लिए इसे फिर से सत्यापित करने से बचने के लिए उपयुक्त हो सकता है, और इसके बजाय इकाई परीक्षणों पर भरोसा कर सकता है।


इसका शीर्षक और पहला पैराग्राफ सही है क्योंकि यह इकाई परीक्षण नहीं है जो रनटाइम पर कोड का उपयोग करेगा। यह जो भी अन्य रनटाइम कोड है और वास्तविक दुनिया की स्थितियों और खराब उपयोगकर्ता इनपुट और हैकिंग प्रयासों को कोड के साथ इंटरैक्ट करता है।
क्रेग

1

दुरुपयोग के खिलाफ रक्षा इसके लिए एक आवश्यकता के कारण विकसित एक विशेषता है। (सभी इंटरफेसों के दुरुपयोग के खिलाफ कठोर जांच की आवश्यकता नहीं है; उदाहरण के लिए आंतरिक रूप से बहुत कम इस्तेमाल होने वाले लोग।)

इस सुविधा के परीक्षण की आवश्यकता है: क्या दुरुपयोग के खिलाफ बचाव वास्तव में काम करता है? इस सुविधा के परीक्षण का लक्ष्य यह दिखाने की कोशिश करना है कि यह नहीं है: मॉड्यूल के कुछ गलत उपयोग को रोकने के लिए जो इसके चेक से नहीं पकड़ा गया है।

यदि विशिष्ट जांच एक आवश्यक विशेषता है, तो वास्तव में यह दावा करना निरर्थक है कि कुछ परीक्षणों का अस्तित्व उन्हें अनावश्यक बनाता है। यदि यह कुछ फ़ंक्शन की एक विशेषता है जो (कहते हैं) यह एक अपवाद फेंकता है जब पैरामीटर तीन नकारात्मक है, तो वह परक्राम्य नहीं है; वह ऐसा करेगा।

हालांकि, मुझे संदेह है कि आपका सहकर्मी वास्तव में ऐसी स्थिति के दृष्टिकोण से समझ बना रहा है जिसमें इनपुट पर विशिष्ट जांच की आवश्यकता नहीं है, खराब इनपुट के लिए विशिष्ट प्रतिक्रियाओं के साथ: ऐसी स्थिति जिसमें केवल एक सामान्य समझ की आवश्यकता है मजबूती।

कुछ शीर्ष स्तर के समारोह में प्रवेश पर चेक, भाग में होते हैं, कुछ कमजोर या बुरी तरह से परीक्षण किए गए आंतरिक कोड को मापदंडों के अनपेक्षित संयोजनों से बचाने के लिए (जैसे कि यदि कोड का अच्छी तरह से परीक्षण किया गया है, तो जांच आवश्यक नहीं है: कोड बस " मौसम "खराब पैरामीटर)।

सहकर्मी के विचार में सच्चाई है, और उसका क्या मतलब है, यह है: यदि हम बहुत मजबूत निचले स्तर के टुकड़ों से एक फ़ंक्शन का निर्माण करते हैं जो रक्षात्मक रूप से कूटबद्ध है और व्यक्तिगत रूप से सभी दुरुपयोग के खिलाफ परीक्षण किया जाता है, तो यह उच्च स्तर के कार्य के लिए संभव है अपनी व्यापक स्व-जांच के बिना मजबूत।

यदि इसके अनुबंध का उल्लंघन किया जाता है, तो यह निचले स्तर के कार्यों के कुछ दुरुपयोग में अनुवाद करेगा, शायद अपवाद या जो कुछ भी फेंकने से।

इसके साथ एकमात्र मुद्दा यह है कि निचले स्तर के अपवाद उच्च स्तर के इंटरफ़ेस के लिए विशिष्ट नहीं हैं। क्या यह एक समस्या है कि क्या आवश्यकताएँ हैं पर निर्भर करता है। यदि आवश्यकता बस है "दुरुपयोग के खिलाफ कार्य मजबूत होगा और क्रैश के बजाय किसी प्रकार के अपवाद को फेंक दें, या कचरा डेटा के साथ गणना करना जारी रखें" तो वास्तव में यह निचले स्तर के टुकड़ों की सभी मजबूती द्वारा कवर किया जा सकता है, जिस पर यह है बनाया।

यदि फ़ंक्शन में इसके मापदंडों से संबंधित बहुत विशिष्ट, विस्तृत त्रुटि रिपोर्टिंग की आवश्यकता है, तो निचले स्तर की जांच उन आवश्यकताओं को पूरी तरह से संतुष्ट नहीं करती है। वे केवल यह सुनिश्चित करते हैं कि फ़ंक्शन किसी भी तरह से उड़ता है (मापदंडों के खराब संयोजन के साथ जारी नहीं है, कचरा परिणाम पैदा करता है)। यदि क्लाइंट कोड को विशेष रूप से कुछ त्रुटियों को पकड़ने और उन्हें संभालने के लिए लिखा गया है, तो यह सही तरीके से काम नहीं कर सकता है। क्लाइंट कोड स्वयं एक इनपुट के रूप में प्राप्त हो सकता है, जिस डेटा पर पैरामीटर आधारित हैं, और यह फ़ंक्शन को इनकी जांच करने और खराब मानों को दस्तावेज के रूप में अनुवाद करने की उम्मीद कर सकता है (ताकि यह उन लोगों को संभाल सके। त्रुटियों को ठीक से) बजाय कुछ अन्य त्रुटियों के जिन्हें संभाला नहीं जाता है और शायद सॉफ्टवेयर छवि को रोकते हैं।

टी एल; DR: आपका सहयोगी शायद एक बेवकूफ नहीं है; आप बस एक ही चीज़ के चारों ओर अलग-अलग दृष्टिकोणों से एक-दूसरे से बात कर रहे हैं, क्योंकि आवश्यकताओं को पूरी तरह से समाप्त नहीं किया गया है और आप में से प्रत्येक को "अलिखित आवश्यकताओं" का एक अलग विचार है। आपको लगता है कि जब पैरामीटर जाँच पर कोई विशिष्ट आवश्यकताएं नहीं होती हैं, तो आपको वैसे भी विस्तृत जाँच को कोड करना चाहिए; सहकर्मी सोचता है, बस मजबूत निचले स्तर के कोड को उड़ा दें जब पैरामीटर गलत हैं। कोड के माध्यम से अलिखित आवश्यकताओं के बारे में बहस करना कुछ हद तक अनुत्पादक है: पहचानें कि आप कोड के बजाय आवश्यकताओं के बारे में असहमत हैं। कोडिंग का आपका तरीका दर्शाता है कि आपको क्या लगता है कि आवश्यकताएं क्या हैं; सहकर्मी का रास्ता आवश्यकताओं के बारे में उनके दृष्टिकोण का प्रतिनिधित्व करता है। यदि आप इसे इस तरह से देखते हैं, तो यह स्पष्ट है कि सही या गलत isn क्या है ' टी कोड में ही; कोड आपकी राय के लिए सिर्फ एक प्रॉक्सी है कि विनिर्देश क्या होना चाहिए।


यह एक सामान्य दार्शनिक कठिनाई से निपटने के साथ जुड़ा हुआ है जो ढीली आवश्यकताएं हो सकती हैं। यदि किसी फ़ंक्शन को महत्वपूर्ण अनुमति दी जाती है, लेकिन कुरूप इनपुट दिए जाने पर मनमाने ढंग से व्यवहार करने के लिए कुल मुक्त शासन नहीं होता है (उदाहरण के लिए यदि कोई छवि विकोडक आवश्यकताओं को पूरा कर सकता है, तो इसकी गारंटी दी जा सकती है - अपने अवकाश पर - या तो पिक्सल के कुछ मनमाने संयोजन का उत्पादन करें या असामान्य रूप से। , लेकिन अगर यह दुर्भावनापूर्ण रूप से तैयार किए गए इनपुट को मनमाने कोड को निष्पादित करने की अनुमति दे सकता है), तो यह स्पष्ट नहीं हो सकता है कि परीक्षण के मामले यह सुनिश्चित करने के लिए उपयुक्त होंगे कि कोई भी इनपुट अस्वीकार्य व्यवहार नहीं करता है।
सुपरकट

1

टेस्ट आपको वर्ग के अनुबंध को परिभाषित करते हैं।

एक कोरोलरी के रूप में, एक परीक्षण की अनुपस्थिति एक अनुबंध को परिभाषित करती है जिसमें अपरिभाषित व्यवहार शामिल है । इसलिए जब आप पास nullहोते हैं Foo::Frobnicate(Widget widget), और रन-टाइम कहर ढाते हैं, तो आप अभी भी अपनी कक्षा के अनुबंध में हैं।

बाद में आप तय करते हैं, "हम अपरिभाषित व्यवहार की संभावना नहीं चाहते हैं", जो एक समझदार विकल्प है। इसका मतलब है कि आपको पास होने के लिए एक अपेक्षित व्यवहार nullकरना होगा Foo::Frobnicate(Widget widget)

और आप उस निर्णय को एक सहित शामिल करते हैं

[Test]
void Foo_FrobnicatesANullWidget_ThrowsInvalidArgument() 
{
    Given(Foo foo);
    When(foo.Frobnicate(null));
    Then(Expect_Exception(InvalidArgument));
}

1

परीक्षणों का एक अच्छा सेट आपकी कक्षा के बाहरी इंटरफ़ेस का उपयोग करेगा और यह सुनिश्चित करेगा कि इस तरह के दुरुपयोग सही प्रतिक्रिया (एक अपवाद, या जो भी आप "सही" के रूप में परिभाषित करते हैं) उत्पन्न करते हैं। वास्तव में, मैं एक क्लास के लिए लिखने वाला पहला टेस्ट केस अपने कंस्ट्रक्टर को आउट ऑफ रेंज तर्कों के साथ बुलाना है।

जिस तरह की रक्षात्मक प्रोग्रामिंग पूरी तरह से इकाई-परीक्षण दृष्टिकोण से समाप्त हो जाती है, वह आंतरिक आक्रमणकारियों की अनावश्यक मान्यता है जिसे बाहरी कोड द्वारा उल्लंघन नहीं किया जा सकता है।

एक उपयोगी विचार जो मैं कभी-कभी नियोजित करता हूं, वह एक ऐसी विधि प्रदान करना है जो वस्तु के अपरिवर्तकों का परीक्षण करता है; आपकी फाड़-फाड़ विधि इसे यह प्रमाणित करने के लिए कह सकती है कि वस्तु पर आपके बाहरी कार्यों को कभी भी नहीं तोड़ना चाहिए।


0

TDD के परीक्षण कोड के विकास के दौरान गलतियों को पकड़ लेंगे ।

रक्षात्मक प्रोग्रामिंग के भाग के रूप में आपके द्वारा जाँचने वाली सीमाएं कोड के उपयोग के दौरान गलतियों को पकड़ लेंगी ।

यदि दो डोमेन समान हैं, तो आप जो कोड लिख रहे हैं, वह केवल इस विशिष्ट परियोजना द्वारा आंतरिक रूप से उपयोग किया जाता है, तो यह सच हो सकता है कि TDD रक्षात्मक प्रोग्रामिंग सीमा की आवश्यकता को समाप्त कर देगा जो आप का वर्णन करते हैं, लेकिन केवल अगर वे तरीके सीमा की जाँच विशेष रूप से टीडीडी परीक्षणों में की जाती है


एक विशिष्ट उदाहरण के रूप में, मान लीजिए कि TDD का उपयोग करके वित्तीय कोड की एक लाइब्रेरी विकसित की गई थी। परीक्षणों में से एक यह दावा कर सकता है कि एक विशेष मूल्य कभी भी नकारात्मक नहीं हो सकता है। यह सुनिश्चित करता है कि लाइब्रेरी के डेवलपर्स गलती से कक्षाओं का दुरुपयोग न करें क्योंकि वे सुविधाओं को लागू करते हैं।

लेकिन पुस्तकालय जारी होने के बाद और मैं इसे अपने कार्यक्रम में उपयोग कर रहा हूं, उन TDD परीक्षणों ने मुझे एक नकारात्मक मान असाइन करने से नहीं रोका (यह मानते हुए कि यह उजागर हुआ है)। चेकिंग की सीमा होगी।

मेरा कहना यह है कि जबकि एक TDD मुखर नकारात्मक मान समस्या का समाधान कर सकता है यदि कोड का उपयोग केवल आंतरिक रूप से एक बड़े अनुप्रयोग (TDD के तहत) के विकास के भाग के रूप में किया जाता है, अगर यह एक प्रोग्राम है जो TDD के बिना अन्य प्रोग्रामर द्वारा उपयोग किया जा रहा है। ढांचा और परीक्षण , मामलों की जाँच की सीमा।


1
मैं नीच नहीं था, लेकिन मैं इस आधार पर नीचे की बात से सहमत हूं कि इस तरह के तर्क में सूक्ष्म अंतर जोड़कर पानी को पिघला देता है।
क्रेग

@ क्रेग मैं आपके द्वारा जोड़े गए विशिष्ट उदाहरण पर आपकी प्रतिक्रिया में दिलचस्पी लेगा।
ब्लैकहॉक

मुझे उदाहरण की विशिष्टता पसंद है। मेरे पास अभी भी एकमात्र चिंता पूरे तर्क के लिए सामान्य है। उदाहरण के लिए; साथ में टीम पर कुछ नए डेवलपर आते हैं और एक नया घटक लिखते हैं जो उस वित्तीय मॉड्यूल का उपयोग करता है। नए आदमी को सिस्टम की सभी पेचीदगियों के बारे में पता नहीं है, अकेले इस तथ्य को बताएं कि सिस्टम को कैसे संचालित करना चाहिए, इसके बारे में सभी प्रकार के विशेषज्ञ ज्ञान कोड के बजाय परीक्षण में एम्बेडेड हैं।
क्रेग

तो नया लड़का / लड़की कुछ महत्वपूर्ण परीक्षण बनाने से चूक जाते हैं, और आप अपने परीक्षणों में अतिरेक के साथ समाप्त हो जाते हैं - सिस्टम के विभिन्न हिस्सों में परीक्षण एक ही स्थिति की जाँच कर रहे हैं, और समय बीतने के साथ असंगत रूप से बढ़ते हैं, बजाय उचित अभिकथन के जहाँ कोड कार्रवाई है, वहां पूर्व शर्त जाँचता है।
क्रेग

1
ऐसा कुछ। सिवाय इसके कि यहाँ बहुत सारे तर्क कॉलिंग टेस्ट के लिए किए गए परीक्षणों के बारे में हैं। लेकिन अगर आपके पास किसी भी तरह का फैन-इन है, तो आप अलग-अलग जगहों के एक समूह से एक ही जांच करवाते हैं, और यह एक मेंटेनेंस इशू है। क्या होगा यदि किसी प्रक्रिया के लिए मान्य इनपुट की सीमा बदल जाती है, लेकिन आपके पास विभिन्न घटकों का उपयोग करने वाले परीक्षणों में निर्मित उस सीमा के लिए डोमेन ज्ञान है? मैं अभी भी पूरी तरह से रक्षात्मक प्रोग्रामिंग के पक्ष में हूं, और यह निर्धारित करने के लिए कि क्या और कब आपके पास प्रदर्शन के मुद्दे हैं, यह निर्धारित करने के लिए प्रोफाइलिंग का उपयोग करें।
क्रेग

0

TDD और रक्षात्मक प्रोग्रामिंग हाथ और हाथ जाओ। दोनों का उपयोग करना बेमानी नहीं है, बल्कि वास्तव में पूरक है। जब आपके पास एक फ़ंक्शन होता है, तो आप यह सुनिश्चित करना चाहते हैं कि फ़ंक्शन वर्णित के रूप में काम करता है और इसके लिए परीक्षण लिखता है; यदि आप खराब इनपुट, खराब रिटर्न, खराब स्थिति आदि के मामले में क्या करते हैं तो कवर नहीं करते हैं, तो आप अपने परीक्षणों को पर्याप्त रूप से नहीं लिख रहे हैं, और आपके सभी परीक्षण पास होने पर भी आपका कोड नाजुक होगा।

एक एम्बेडेड इंजीनियर के रूप में, मैं केवल दो बाइट्स को एक साथ जोड़ने और इस तरह से परिणाम वापस करने के लिए एक फ़ंक्शन लिखने के उदाहरण का उपयोग करना पसंद करता हूं:

uint8_t AddTwoBytes(uint8_t a, uint8_t b, uint8_t *sum); 

अब अगर आप बस *(sum) = a + bकरते हैं तो यह काम करेगा, लेकिन केवल कुछ इनपुट के साथ । a = 1और b = 2बनाना होगा sum = 3; हालाँकि, क्योंकि योग का आकार एक बाइट है, a = 100और अतिप्रवाह के कारण b = 200बना होगा sum = 44। सी में, आप इस मामले में त्रुटि को इंगित करेंगे कि फ़ंक्शन को विफल करने के लिए; अपवाद को फेंकना आपके कोड में एक ही बात है। असफलता या परीक्षण पर विचार न करना कि उन्हें कैसे संभालना है, दीर्घकालिक काम नहीं करेगा, क्योंकि यदि वे स्थितियां होती हैं, तो उन्हें संभाला नहीं जाएगा और किसी भी संख्या में मुद्दों का कारण बन सकता है।


यह एक अच्छा साक्षात्कार-प्रश्न उदाहरण की तरह दिखता है (इसका रिटर्न मान और "आउट" पैरामीटर क्यों है - और जब sumएक अशक्त सूचक होता है तो क्या होता है?)।
टोबे स्पाइट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.