एक मित्र वर्ग का उपयोग करके c ++ में यूनिट टेस्ट प्राइवेट विधि


15

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

1) एक मित्र को उस वर्ग का बनाइए जिसकी विधि मैं परीक्षण करना चाहता हूँ।

2) मित्र वर्ग में, एक सार्वजनिक विधि (ओं) का निर्माण करें जो परीक्षण किए गए वर्ग की निजी पद्धति (ओं) को कहते हैं।

3) मित्र वर्ग के सार्वजनिक तरीकों का परीक्षण करें।

उपरोक्त चरणों का वर्णन करने के लिए यहां एक सरल उदाहरण दिया गया है:

#include <iostream>

class MyClass
{
  friend class MyFriend; // Step 1

  private:
  int plus_two(int a)
  {
    return a + 2;
  }
};

class MyFriend
{
public:
  MyFriend(MyClass *mc_ptr_1)
  {
    MyClass *mc_ptr = mc_ptr_1;
  }

  int plus_two(int a) // Step 2
  {
    return mc_ptr->plus_two(a);
  }
private:
  MyClass *mc_ptr;
};

int main()
{
  MyClass mc;
  MyFriend mf(&mc);
  if (mf.plus_two(3) == 5) // Step 3
    {
      std::cout << "Passed" << std::endl;
    }
  else
    {
      std::cout << "Failed " << std::endl;
    }

  return 0;
}

संपादित करें:

मैं देखता हूं कि एक उत्तर के बाद चर्चा में लोग मेरे कोड आधार के बारे में सोच रहे हैं।

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

ऊपर कहा गया है, मेरा सवाल यह नहीं था कि क्या निजी तरीकों के लिए यूनिट परीक्षण लिखने के लिए यह एक अच्छा अभ्यास है, हालांकि मैं प्रतिक्रिया की सराहना करता हूं।


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

4
@JTrana: क्यों नहीं लिखा है कि एक उचित जवाब के रूप में?
बार्ट वैन इनगेन शानौ

ठीक है। यह उन लोगों में से नहीं है जिनके बारे में आप सुपर-गर्व महसूस करते हैं, लेकिन उम्मीद है कि यह मदद करेगा।
जे ट्राना

जवाबों:


23

दोस्त के लिए एक विकल्प (अच्छी तरह से, एक अर्थ में) जो मैं अक्सर उपयोग करता हूं वह एक पैटर्न है जिसे मुझे एक्सेस_बाय के रूप में पता चला है। यह बहुत आसान है:

class A {
  void priv_method(){};
 public:
  template <class T> struct access_by;
  template <class T> friend struct access_by;
}

अब, मान लीजिए कि वर्ग B परीक्षण में शामिल है। आप इसे लिख सकते हैं:

template <> struct access_by<B> {
  call_priv_method(A & a) {a.priv_method();}
}

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


के लिए एक वैध उपयोग के मामले के बारे में उत्सुक friend access_by, पहले गैर दोस्त पर्याप्त नहीं है - एक नेस्टेड संरचना होने के नाते यह ए से सब कुछ तक पहुंच होगा? जैसे। coliru.stacked-crooked.com/a/663dd17ed2acd7a3
tangy

10

यदि परीक्षण करना कठिन है, तो यह बुरी तरह से लिखा गया है

यदि आपके पास निजी तरीकों के साथ एक वर्ग है जो अपने स्वयं के परीक्षण को वारंट करने के लिए पर्याप्त है, तो कक्षा बहुत अधिक कर रही है। अंदर एक और वर्ग बाहर निकलने की कोशिश कर रहा है।

उन निजी तरीकों को निकालें जिन्हें आप एक नई कक्षा (या कक्षाओं) में परीक्षण करना चाहते हैं और उन्हें सार्वजनिक करना चाहते हैं। नई कक्षाओं का परीक्षण करें।

कोड को परीक्षण करने में आसान बनाने के अलावा, यह रिफैक्टिंग कोड को समझने और बनाए रखने में आसान बना देगा।


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

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

1
@ नीर: तुच्छ कार्य करें: उन सभी विधियों को सार्वजनिक करने के साथ एक वर्ग निकालें, और अपने मौजूदा वर्ग को नए वर्ग के चारों ओर मोड़ दें।
केविन क्लाइन

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

4

आपको निजी तरीकों का परीक्षण नहीं करना चाहिए। अवधि। आपकी कक्षा का उपयोग करने वाले वर्ग केवल उन तरीकों के बारे में परवाह करते हैं जो यह प्रदान करता है, न कि यह जो हुड के तहत काम करता है।

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


6
निजी तरीकों का मतलब विकास को कम करना है (चिंताओं को अलग करना, या DRY, या किसी भी चीज़ को बनाए रखना) लेकिन गैर-स्थायी होना चाहिए। वे उस कारण से निजी हैं। वे एक कार्यान्वयन से दूसरे में बहुत तेजी से कार्यक्षमता में प्रकट हो सकते हैं, गायब हो सकते हैं या बदल सकते हैं, यही कारण है कि उन्हें यूनिट परीक्षणों के लिए बांधना हमेशा व्यावहारिक या उपयोगी नहीं होता है।
Ampt

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

2
मुझे यह भी ध्यान दें: ओपी ने कहा कि वह जानता है कि यह एक बहस का अभ्यास है। इसलिए यदि वह इसे वैसे भी करना चाहता है, तो शायद उसके पास इसके अच्छे कारण हैं? न तो हम उसके कोडबेस का विवरण जानते हैं। मेरे साथ काम करने वाले कोड में, हमारे पास कुछ बहुत ही अनुभवी और विशेषज्ञ प्रोग्रामर हैं, और उन्होंने सोचा कि यह कुछ मामलों में निजी तरीकों का परीक्षण करने के लिए उपयोगी था।
निर फ्रीडमैन

2
-1, "आपको निजी तरीकों का परीक्षण नहीं करना चाहिए" जैसा उत्तर। IMHO मददगार नहीं है इस साइट पर कब और कैसे परीक्षण करना है, इस विषय पर पर्याप्त रूप से चर्चा की गई है। ओपी ने दिखाया है कि वह इस चर्चा से अवगत है, और इसके स्पष्ट रूप से वह इस धारणा के तहत समाधान तलाश रहा है कि उसके मामले में निजी तरीकों का परीक्षण करने का तरीका क्या है।
डॉक्टर ब्राउन 5

3
मुझे लगता है कि यहां समस्या यह है कि यह एक बहुत ही क्लासिक XY समस्या हो सकती है जिसमें ओपी को लगता है कि उसे एक या दूसरे कारण से अपने निजी तरीकों का परीक्षण करने की आवश्यकता है, जब वास्तव में वह अधिक व्यावहारिक दृष्टिकोण से परीक्षण को देख सकता है, तो निजी देखना जनता के लिए केवल सहायक कार्यों के रूप में विधियां, जो वर्ग के अंतिम उपयोगकर्ताओं के साथ अनुबंध हैं।
Ampt

3

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

  • आप परीक्षण किए गए वर्ग में एक मित्र (वर्ग या कार्य) घोषणा जोड़ सकते हैं।

  • आप परीक्षण कोड #define private publicसे पहले, अपनी परीक्षण फ़ाइलों की शुरुआत में जोड़ सकते हैं #include। यदि परीक्षण किया गया कोड पहले से ही संकलित पुस्तकालय है, तो इससे हेडर अब पहले से संकलित बाइनरी कोड (और यूबी का कारण) से मेल नहीं खा सकता है।

  • आप अपने परीक्षण किए गए वर्ग में एक मैक्रो सम्मिलित कर सकते हैं और बाद की तारीख में तय कर सकते हैं कि मैक्रो का क्या मतलब है (परीक्षण कोड के लिए एक अलग परिभाषा के साथ)। यह आपको इंटर्नल का परीक्षण करने की अनुमति देगा, लेकिन यह तीसरे पक्ष के क्लाइंट कोड को आपकी कक्षा में हैक करने की भी अनुमति देगा (आपके द्वारा घोषित घोषणा में अपनी स्वयं की परिभाषा बनाकर)।


2

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

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

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


हालांकि यह एक जावा दृष्टिकोण है, यह एक ही पैकेज (परीक्षण कक्षाओं) में अन्य कक्षाओं को देखने की अनुमति देने के बजाय निजी कार्यों को डिफ़ॉल्ट स्तर बनाने के लिए काफी मानक है।

0

आप दोस्तों का उपयोग करने से रोकने के लिए अपने कोड को बहुत सारे कार्यपट्टों के साथ लिख सकते हैं।

आप कक्षाएं लिख सकते हैं और कभी भी कोई भी निजी तरीका नहीं अपना सकते हैं। इसके बाद आपको केवल संकलन इकाई के भीतर कार्यान्वयन कार्य करना है, अपनी कक्षा को उन्हें कॉल करने दें और उन किसी भी डेटा सदस्यों को पास करें जिन्हें उन्हें एक्सेस करने की आवश्यकता है।

और हां इसका मतलब होगा कि आप भविष्य में अपने हेडर को बदले बिना हस्ताक्षर बदल सकते हैं या नए "कार्यान्वयन" तरीके जोड़ सकते हैं।

आपको वजन करना होगा, हालांकि यह इसके लायक है या नहीं। और वास्तव में बहुत कुछ इस बात पर निर्भर करेगा कि आपका हेडर कौन देख रहा है।

अगर मैं एक 3 पार्टी लाइब्रेरी का उपयोग कर रहा हूं तो मैं उनकी यूनिट परीक्षकों को मित्र घोषणाएं नहीं देखूंगा। मैं उनके पुस्तकालय का निर्माण नहीं करना चाहता और जब मैं करता हूं तो उनके परीक्षण चलते हैं। दुर्भाग्य से बहुत सारे 3 पार्टी ओपन सोर्स लाइब्रेरी मैंने बनाए हैं जो ऐसा करते हैं।

परीक्षण पुस्तकालय के लेखकों का काम है, न कि इसके उपयोगकर्ताओं का।

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

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

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