2010-11-13 12 views
47

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

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

न ही मुझे संरक्षित सदस्यों के समूह के बारे में चिंता करना है कि मुझे यह जानने की आवश्यकता नहीं है कि मुझे कक्षा से विरासत मिल रही है या नहीं।

यही कारण है कि मैं कहता हूं कि यह अमूर्तता और encapsulation को संरक्षित करता है।

मेरी नई नौकरी पर वे यूनिट परीक्षणों के लिए भी मित्र वर्गों का उपयोग करने के खिलाफ फंस गए। वे कहते हैं क्योंकि कक्षा को परीक्षणों के बारे में कुछ भी नहीं पता होना चाहिए और आप कक्षा और उसके परीक्षण के तंग युग्मन को नहीं चाहते हैं।

क्या कोई मुझे इन कारणों को और अधिक समझा सकता है ताकि मैं बेहतर समझ सकूं? मैं सिर्फ यह नहीं देखता कि यूनिट परीक्षणों के लिए किसी मित्र का उपयोग क्यों खराब है।

+0

मुझे आश्चर्य है, अगर उन्होंने कुछ विकल्प भी पेश किए हैं? –

+0

विकल्पों को सार्वजनिक इंटरफ़ेस का उपयोग करके विधि का आह्वान करने का एक तरीका मिल गया था; इसे संरक्षित और कक्षा का विस्तार करें; – cchampion

+3

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

उत्तर

51

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

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

+10

+1 कि बहुत से निजी तरीकों को अक्सर किसी अन्य कक्षा में सार्वजनिक किया जा सकता है। – Philipp

+6

मैं इससे असहमत हूं। यदि आप एक जटिल एल्गोरिदम लागू कर रहे हैं और इसे छोटे चरणों में तोड़ना चाहते हैं (यह इस एल्गोरिदम के कार्यान्वयन के बाहर पूरी तरह से बेकार होगा) कदमों को निजी कार्यान्वयन के विवरण के रूप में रखने में कुछ भी गलत नहीं है कि कोड में कोई अन्य ऑब्जेक्ट नहीं है पहुंचने में सक्षम होना चाहिए, और अभी भी यह जांचना चाहते हैं कि प्रत्येक उप-चरण सही इनपुट के सही परिणाम देता है। @ Jean-MichaëlCelerier के लिए –

+1

+ 1। आपके पास एक लंबा ** फ़ंक्शन हो सकता है जो सार्वजनिक है या इसे तार्किक भागों में विभाजित कर सकता है। लेकिन तार्किक भागों को सार्वजनिक होना जरूरी नहीं है। हालांकि, उन्हें परीक्षण करने की आवश्यकता है। पूर्व। एक छवि का एक परिवर्तन जहां यह warped है। – navderm

4

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

class Myclass 
{ 
#if defined(UNIT_TEST) 
    friend class UnitTest; 
#endif 
}; 

यूनिट परीक्षण की आवश्यकता होने पर केवल ध्वज UNIT_TEST सक्षम करें। अन्य रिलीज के लिए, आपको इस ध्वज को अक्षम करने की आवश्यकता है।

12

आपको यह समझना चाहिए कि परीक्षण करने के लिए विभिन्न शैलियों और विधियां हैं: Black box testing केवल सार्वजनिक इंटरफेस का परीक्षण करता है (क्लास को ब्लैक बॉक्स के रूप में पेश करता है)। यदि आपके पास एक सार आधार श्रेणी है तो आप अपने सभी कार्यान्वयन के खिलाफ भी उसी परीक्षण का उपयोग कर सकते हैं।

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

जैसा कि बीकैट ने बताया, यह अक्सर कई निजी तरीकों के बजाय संरचना और अधिक छोटे वर्गों का उपयोग करने में मददगार होता है। यह सफेद बॉक्स परीक्षण को सरल बनाता है क्योंकि आप एक अच्छा परीक्षण कवरेज प्राप्त करने के लिए परीक्षण मामलों को अधिक आसानी से निर्दिष्ट कर सकते हैं।

1

आमतौर पर आप केवल सार्वजनिक इंटरफ़ेस का परीक्षण करते हैं ताकि आप पुन: डिज़ाइन और कार्यान्वयन को दोबारा मुक्त कर सकें। निजी सदस्यों के लिए टेस्ट केस जोड़ना आपकी कक्षा के कार्यान्वयन पर एक आवश्यकता और प्रतिबंध को परिभाषित करता है।

4

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

0

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

+0

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

9

मुझे लगता है कि Bcat एक बहुत अच्छा जवाब दिया है, लेकिन मैं असाधारण मामला है कि वह

असली दुनिया में की ओर संकेत पर व्याख्या करने के लिए चाहते हैं, बातें हमेशा इतना स्पष्ट नहीं हो सकता है, और एक होने इकाई परीक्षण वर्ग कक्षा का मित्र बनता है, यह परीक्षण स्वीकार्य, या यहां तक ​​कि वांछनीय भी हो सकता है।

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

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

कुछ मामलों में मजाक बाद समस्या को कम करने के लिए उपयोगी है, लेकिन बहुत बार यह सिर्फ निम्नलिखित में, जबकि एक बहुत बस कोड refactor सकता uneccessarily जटिल डिजाइन (कक्षा heirarchies जहां कोई भी अन्यथा की जरूरत होगी) की ओर जाता है, रास्ता:

class Foo{ 
public: 
    some_db_accessing_method(){ 
     // some line(s) of code with db dependance. 

     // a bunch of code which is the real meat of the function 

     // maybe a little more db access. 
    } 
} 

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

class Foo{ 
public: 
    some_db_accessing_method(){ 
     // db code as before 
     unit_testable_meat(data_we_got_from_db); 
     // maybe more db code.  
} 
private: 
    unit_testable_meat(...); 
} 

बाद मुझे सभी लाभों मैं इकाई परीक्षण से जरूरत के देता है, मुझे दे रही है कि कीमती सुरक्षा तंत्र जब उत्पादित त्रुटियों को पकड़ने के लिए सहित:

एक कहीं अधिक व्यावहारिक दृष्टिकोण इस तरह कुछ करने के लिए किया जाएगा मैं मांस में कोड refactor।यूनिट परीक्षण करने के लिए, मुझे यूनिटटेस्ट क्लास से मिलना है, लेकिन मैं दृढ़ता से तर्क दूंगा कि यह एक अन्यथा बेकार कोड विरासत से कहीं बेहतर है जो मुझे नकली उपयोग करने की अनुमति देता है।

मुझे लगता है कि यह एक मुहावरे बनना चाहिए, और मुझे लगता है कि यह इकाई परीक्षण के आरओआई को बढ़ाने के लिए एक उपयुक्त, व्यावहारिक समाधान है।

संबंधित मुद्दे