टीडीडी: कसकर युग्मित वस्तुओं को बाहर करना


10

कभी-कभी वस्तुओं को केवल कसकर युग्मित करने की आवश्यकता होती है। उदाहरण के लिए, एक CsvFileवर्ग को संभवतः CsvRecordकक्षा (या ICsvRecordइंटरफ़ेस) के साथ कसकर काम करने की आवश्यकता होगी ।

हालाँकि मैंने अतीत में जो कुछ भी सीखा था, उसमें से एक परीक्षण-संचालित विकास के मुख्य सिद्धांतों में से एक है "कभी भी एक समय में एक से अधिक कक्षा का परीक्षण न करें।" मतलब आपको ICsvRecordवास्तविक उदाहरणों के बजाय मोक्स या स्टब्स का उपयोग करना चाहिए CsvRecord

हालाँकि इस दृष्टिकोण को आजमाने के बाद, मैंने देखा कि CsvRecordक्लास में नकल करने से थोड़े बाल निकल सकते हैं। जो मुझे दो निष्कर्षों में से एक की ओर ले जाता है:

  1. इकाई परीक्षण लिखना कठिन है! यह एक कोड गंध है! Refactor!
  2. हर एक निर्भरता का मजाक उड़ाना अनुचित है।

जब मैंने अपने मोक्स को वास्तविक CsvRecordउदाहरणों से बदल दिया , तो चीजें बहुत आसानी से चली गईं। जब अन्य लोगों के विचारों की तलाश में मैं इस ब्लॉग पोस्ट पर ठोकर खाई , जो ऊपर # 2 का समर्थन करता है। उन वस्तुओं के लिए जो स्वाभाविक रूप से कसकर युग्मित हैं, हमें मॉकिंग के बारे में इतनी चिंता नहीं करनी चाहिए।

क्या मैं पटरी से उतर रहा हूँ? क्या # 2 ऊपर मानने के लिए कोई डाउनसाइड है? क्या मुझे वास्तव में अपने डिजाइन को फिर से बनाने के बारे में सोचना चाहिए?


1
मुझे लगता है कि यह एक आम गलत धारणा है कि "यूनिट टेस्ट" में "यूनिट" जरूरी एक वर्ग होना चाहिए। मुझे लगता है कि आपका उदाहरण एक मामला दिखाता है जहां यह बेहतर हो सकता है कि वे दो वर्ग एक इकाई बनाते हैं। लेकिन मुझे गलत मत समझो, मैं रॉबर्ट हार्वे के जवाब से पूरी तरह सहमत हूं।
डॉक ब्राउन

जवाबों:


11

यदि आपको वास्तव में उन दो वर्गों के बीच समन्वय की आवश्यकता है, तो एक ऐसी CsvCoordinatorकक्षा लिखें, जो आपकी दो कक्षाओं को एनकैप्सुलेट करती है, और वह परीक्षण करती है।

हालांकि, मैं इस धारणा को विवादित करता हूं कि CsvRecordस्वतंत्र रूप से परीक्षण योग्य नहीं है। CsvRecordमूल रूप से एक DTO वर्ग है, है ना? यह सिर्फ खेतों का एक संग्रह है, शायद सहायक विधियों के एक जोड़े के साथ। और CsvRecordइसके अलावा अन्य संदर्भों में इस्तेमाल किया जा सकता है CsvFile; CsvRecordउदाहरण के लिए, आपके पास संग्रह या सारणी हो सकती है ।

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


1
हां, CsvRecord सबसे निश्चित रूप से स्वतंत्र रूप से परीक्षण योग्य है। समस्या यह है कि यदि CsvRecord में कुछ टूट जाता है, तो यह CsvData परीक्षण विफल हो जाएगा। लेकिन मुझे नहीं लगता कि यह एक प्रमुख मुद्दा है।
फिल

1
मुझे लगता है कि आप चाहते हैं कि ऐसा हो। :)
रॉबर्ट हार्वे

1
@RobertHarvey: सिद्धांत रूप में, यह एक समस्या बन सकता है यदि CsvRecord और CsvFile काफी जटिल वर्ग बन रहे हैं, और यदि CsvFile के लिए एक परीक्षण टूट जाता है, तो अब आप तुरंत नहीं जानते कि यह CsvFile या CsvRecord में कोई समस्या है या नहीं। लेकिन मुझे लगता है कि यह एक काल्पनिक मामला है - अगर मुझे वास्तविक दुनिया के कार्यक्रम के लिए ऐसी कक्षाओं को प्रोग्रामिंग करने का कार्य मिला है, तो मैं इसे ठीक उसी तरह से करूंगा जिस तरह से आप इसका वर्णन करते हैं।
डॉक ब्राउन

2
@ पिल: अगर CsvRecordटूटता है, तो जाहिर तौर पर CsvDataविफल रहता है; लेकिन यह ठीक है, क्योंकि आप CsvRecordपहले परीक्षण करते हैं , और यदि वह विफल रहता है, तो आपके CsvFileपरीक्षण अर्थहीन हैं। आप अभी भी अंदर CsvRecordऔर त्रुटियों के बीच अंतर कर सकते हैं CsvFile
tdammers

5

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

एक वर्ग CsvRecordमुझे लगता है कि यह ज्यादातर डेटा संग्रहीत करने के लिए है - यह अपनी खुद की बहुत अधिक कार्यक्षमता वाला वर्ग नहीं है। यही है, इसमें कंस्ट्रक्टर, गेटर्स, सेटर हो सकते हैं, लेकिन वास्तविक पर्याप्त तर्क के साथ कोई विधियां नहीं हैं। बेशक, मैं यहाँ अनुमान लगा रहा हूँ - शायद आपने एक वर्ग लिखा CsvRecordहै, जो कई जटिल गणनाएँ करता है।

लेकिन अगर CsvRecordइसका वास्तविक तर्क नहीं है, तो इसका मजाक उड़ाने से कुछ हासिल नहीं होगा। यह वास्तव में सिर्फ पुरानी कहावत है - "वस्तुओं का अपमान न करें"

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


+1। कोई भी परीक्षण जिसका परिणाम एक से अधिक वस्तु के व्यवहार की शुद्धता पर निर्भर करता है, एक एकीकरण परीक्षण है, न कि एक इकाई परीक्षण। आपको वास्तविक इकाई परीक्षण प्राप्त करने के लिए इन वस्तुओं में से एक का मजाक उड़ाना होगा। यह उन में कोई वास्तविक व्यवहार के साथ वस्तुओं पर लागू नहीं होता है, हालांकि केवल उदाहरण के लिए प्राप्त होता है और बसता है।
guillaume31

1

नंबर # 2 ठीक है। चीजें हो सकती हैं, और अगर उनकी अवधारणाओं को कसकर युग्मित किया जाए तो उन्हें कसकर जोड़ा जाना चाहिए । यह दुर्लभ होना चाहिए, और आम तौर पर बचा जाना चाहिए, लेकिन उदाहरण में आपने इसे प्रदान किया है।


0

"युग्मित" वर्ग परस्पर एक दूसरे पर निर्भर होते हैं । यह इस बात में नहीं होना चाहिए कि आप क्या वर्णन कर रहे हैं - एक CsvRecord को वास्तव में CsvFile युक्त के बारे में परवाह नहीं करनी चाहिए, इसलिए निर्भरता केवल एक ही रास्ता है। यह ठीक है, और तंग युग्मन नहीं है

आखिरकार, यदि किसी वर्ग में चर स्ट्रिंग नाम होता है, तो आप यह दावा नहीं करेंगे कि यह स्ट्रिंग के साथ युग्मित है, आप करेंगे?

तो, यूनिट अपने इच्छित व्यवहार के लिए CsvRecord का परीक्षण करती है।

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

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


1
-1, चुस्त युग्मन का मतलब जरूरी नहीं कि चक्रीय निर्भरता हो, यह एक गलत धारणा है। उदाहरण में, CsvFile है कसकर के लिए युग्मित CsvRecord(लेकिन इसके विपरीत)। ओपी पूछता है कि क्या यह एक अच्छा विचार है CsvFileजो इसे CsvRecordएक के माध्यम से डिकॉउप्ल करके टेस्ट करता है ICsvRecord, न कि इसके विपरीत।
डॉक ब्राउन

2
@DocBrown: कपलिंग टाइट है या नहीं यह इस बात का विषय है कि CsvFileइनर कामकाज की CsvRecordमात्रा पर निर्भर करता है, यानी फ़ाइल के रिकॉर्ड के बारे में मान्यताओं की मात्रा। इंटरफेस मदद करते हैं और ऐसी मान्यताओं (या बल्कि अन्य मान्यताओं की अनुपस्थिति) को लागू करते हैं, लेकिन युग्मन की मात्रा समान रहती है, सिवाय इसके कि एक इंटरफ़ेस के साथ, आप एक अलग रिकॉर्ड क्लास को हुक कर सकते हैं CsvFile। इंटरफ़ेस का परिचय सिर्फ इतना है कि आप कह सकते हैं कि आपने कपलिंग को कम कर दिया है।
tdammers

0

यहाँ वास्तव में दो प्रश्न हैं। पहली यह है कि ऐसी परिस्थितियाँ मौजूद हैं जहाँ किसी वस्तु का मज़ाक उड़ाना अनुचित है। यह निस्संदेह सच है, जैसा कि अन्य उत्कृष्ट उत्तरों द्वारा दिखाया गया है। दूसरा सवाल यह है कि क्या आपका विशेष मामला उन स्थितियों में से एक है। उस सवाल पर मैं आश्वस्त नहीं हूं।

शायद एक वर्ग का मजाक न उड़ाने का सबसे आम कारण यह है कि यह एक मूल्य वर्ग है। हालांकि, आपको नियम के पीछे के कारण को देखना होगा। यह इसलिए नहीं है कि नकली वर्ग किसी तरह खराब होगा, यह इसलिए है क्योंकि यह मूल रूप से समान होगा। यदि ऐसा होता, तो मूल इकाई का उपयोग करके आपकी इकाई परीक्षण आसान नहीं होता।

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

ज्यादातर लोगों को लगता है कि आप CsvRecordएक मूल्य वर्ग है। इसे एक बनाने की कोशिश करें। यदि आप कर सकते हैं तो इसे अपरिवर्तनीय बनाएं। यदि आपके पास एक दूसरे के लिए संकेत के साथ दो ऑब्जेक्ट हैं, तो उनमें से एक को हटा दें और यह पता लगाएं कि यह कैसे काम करता है। वर्गों और कार्यों को विभाजित करने के लिए स्थानों की तलाश करें। क्लास को विभाजित करने के लिए सबसे अच्छी जगह हमेशा फ़ाइल के भौतिक लेआउट के साथ मेल नहीं खा सकती है। कक्षाओं के मूल / बच्चे के संबंध को उलटने का प्रयास करें। शायद आपको सीएसवी फ़ाइलों को पढ़ने और लिखने के लिए एक अलग वर्ग की आवश्यकता है। हो सकता है कि आपको फ़ाइल I / O और ऊपरी परतों के इंटरफ़ेस को संभालने के लिए अलग-अलग कक्षाओं की आवश्यकता हो। इसे अपरिवर्तनीय घोषित करने से पहले बहुत सी चीजें आजमाई जानी हैं।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.