2008-11-23 14 views
13

क्या इकाई परीक्षण विनाशकों के लिए कोई अच्छा तरीका है? जैसा कहते हैं कि मैं इस (काल्पनिक) के उदाहरण की तरह एक वर्ग है:इकाई परीक्षण विनाशक?

class X 
{ 
private: 
    int *x; 

public: 
    X() 
    { 
     x = new int; 
    } 

    ~X() 
    { 
     delete x; 
    } 

    int *getX() {return x;} 
    const int *getX() const {return x;} 
}; 

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

उत्तर

7

निर्भरता इंजेक्शन के लिए कुछ कहा जा सकता है। किसी ऑब्जेक्ट को बनाने के बजाए (इस मामले में एक int, लेकिन एक गैर-प्रदूषित मामले में उपयोगकर्ता द्वारा परिभाषित प्रकार की संभावना अधिक है) इसके कन्स्ट्रक्टर में, ऑब्जेक्ट को कन्स्ट्रक्टर के पैरामीटर के रूप में पास किया जाता है। यदि ऑब्जेक्ट बाद में बनाया गया है, तो एक्स

के निर्माता के लिए एक कारखाना पारित किया जाता है, फिर जब आप इकाई परीक्षण करते हैं, तो आप एक नकली वस्तु (या एक नकली कारखाना जो नकली वस्तुओं को बनाता है), और विनाशक इस तथ्य को रिकॉर्ड करता है कि इसे बुलाया गया है। परीक्षण विफल रहता है अगर यह नहीं है।

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

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

+0

निश्चित रूप से मैं क्या कह रहा था –

+1

हाँ, और लगभग उसी समय बिल्कुल।मुझे लगता है कि मैंने जीता क्योंकि आपने कोड नमूना लिखना बंद कर दिया :-) –

0

कुछ कंपाइलर डिबग पॉइंटर्स तक पहुंच का पता लगाने में सहायता के लिए डीबग मोड में ज्ञात पैटर्न के साथ हटाए गए मेमोरी को ओवरराइट कर देंगे। मुझे पता है कि 0xDD का उपयोग करने के लिए विज़ुअल सी ++ का उपयोग किया जाता है, लेकिन मैंने इसे थोड़ी देर में उपयोग नहीं किया है।

अपने परीक्षण मामले में, आप एक्स की एक प्रति स्टोर कर सकते हैं, यह क्षेत्र से बाहर जाने के लिए और यह सुनिश्चित करें कि * x == 0xDDDDDDDD करते हैं:

void testDestructor() 
{ 
    int *my_x; 
    { 
     X object; 
     my_x = object.getX(); 
    } 
    CPPUNIT_ASSERT(*my_x == 0xDDDDDDDD); 
} 
+0

मैं इस विचार को तुच्छ जानता हूं। आप ऑप्टिमाइज़ेशन सक्षम के साथ यूनिट टेस्ट कोड नहीं कर सकते हैं या यदि आपका कंपाइलर –

+0

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

1

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

मुझे एक सिंगलटन में विनाशक कॉल को नष्ट करने के बजाय सी ++ में ऐसा करने के किसी भी अन्य तरीके से नहीं पता है कि यह नष्ट हो गया है। मैं एक कमजोर संदर्भ का उपयोग कर सी # में ऐसा कुछ करने के लिए एक विधि के साथ आया हूं (मैं इस दृष्टिकोण के साथ encapsulation या abstractions का उल्लंघन नहीं करता)। मैं सी ++ के समानता के साथ आने के लिए पर्याप्त रचनात्मक नहीं हूं, लेकिन आप हो सकते हैं। अगर यह मदद करता है, महान, अगर नहीं, माफ करना।

http://houseofbilz.com/archive/2008/11/11/writing-tests-to-catch-memory-leaks-in-.net.aspx

0

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

1

उदाहरण में, अपना खुद का वैश्विक नया परिभाषित करें और हटाएं।

#ifdefs से बचने के लिए, मैंने टेस्ट क्लास दोस्तों को बनाया है। आप कॉल के परिणामों को सत्यापित करने के लिए आवश्यकतानुसार राज्य को सेट/सेव/प्राप्त कर सकते हैं।

+0

यह विचार स्केल नहीं करता है। क्या होगा यदि आपको कई अलग-अलग वर्गों का परीक्षण करने की आवश्यकता है, तो क्या आप अपने वैश्विक नए संस्करणों को लागू करने और हटाने के लिए जा रहे हैं? क्या होगा यदि आप यूनिट परीक्षण कोड हैं जो पहले से ही बदलता है :: नया और :: हटाएं? –

+0

मुझे नहीं पता कि आपकी कल्पना किस स्ट्रॉ आदमी है। उपकरण का उद्देश्य "एक्स एक्स आवंटित" जैसे प्रश्नों का उत्तर देना है? अन्य उत्तर यहां नियंत्रण को नियंत्रित करने के बजाय स्मृति उपकरण के एक मंच विशिष्ट संस्करण का लाभ उठाते हैं। –

+0

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

5

मुझे लगता है कि आपकी समस्या यह है कि आपका वर्तमान उदाहरण टेस्ट करने योग्य नहीं है। चूंकि आप जानना चाहते हैं कि x हटा दिया गया था, तो आपको वास्तव में x को नकली के साथ बदलने में सक्षम होना चाहिए। यह शायद एक int के लिए थोड़ा ओटीटी है लेकिन मुझे लगता है कि आपके असली उदाहरण में आपके पास कुछ अन्य वर्ग है। यह परीक्षण योग्य बनाने के लिए, X निर्माता वस्तु int इंटरफेस को लागू करने के लिए पूछने की जरूरत है:

template<class T> 
class X 
{ 
    T *x; 
    public: 
    X(T* inx) 
    : x(inx) 
    { 
    } 

    // etc 
}; 

अब यह x के लिए मूल्य में उपहास करने के लिए सरल हो जाता है, और नकली सही विनाश के लिए जाँच संभाल कर सकते हैं।

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

+0

यह एक int के लिए ऐसा करने का एकमात्र तरीका है, लेकिन एक वर्ग टेम्पलेट कक्षा के लिए एक छोटा सा प्रतिस्थापन नहीं है। टेम्पलेट्स का उपयोग करना हर जगह आम तौर पर डीएलएल के लिए आपके विकल्पों को सीमित करता है, हेडर निर्भरता को कम करता है, आदि। सभी पाठ्यक्रम के कंपाइलर पर निर्भर करता है: मुझे दूसरों से तुलना में कुछ बेहतर टेम्पलेट जोड़ने का समर्थन किया गया है। –

+0

आपको याद है, शायद मैं सिर्फ अजीब हूँ क्योंकि मैंने कहा था कि आप एक बिल्टिन प्रकार का नकल नहीं कर सकते हैं, जैसा कि आपने बताया है कि झूठा है, क्योंकि आप इसे इस तरह से टेम्पलेट्स और कक्षा के माध्यम से कर सकते हैं जो पूरे लागू करता है int इंटरफेस (तुच्छ नहीं है, लेकिन आपको केवल एक बार ऐसा करना है। numeric_limits को मत भूलना)। –

+0

ठीक है आपको इसे टेम्पलेटिज्ड बनाना नहीं होगा। यदि आपने टेम्पलेट को हटा दिया है और टी को हर जगह int में बदल दिया है तो यह अभी भी टेस्टेबल होगा –

1

यह उस व्यक्ति से प्रासंगिक नहीं होगा जिसने प्रश्न पूछा था लेकिन यह पढ़ने वाले अन्य लोगों के लिए सहायक हो सकता है। मुझे नौकरी साक्षात्कार में एक समान प्रश्न पूछा गया था।

मान लिया जाये कि स्मृति सीमित है, तो आप इस विधि का प्रयास कर सकते हैं:

  1. स्मृति आवंटित जब तक आवंटन (नाशक के लिए किसी भी प्रासंगिक परीक्षण चलाने से पहले) स्मृति संदेश से बाहर के साथ विफल रहता है और स्मृति के आकार को बचाने के परीक्षण चलाने से पहले उपलब्ध है।
  2. परीक्षण चलाएं (कन्स्ट्रक्टर को कॉल करें और जैसा कि आप नए उदाहरण पर चाहते हैं कुछ क्रियाएं करें)।
  3. विनाशक को चलाएं।
  4. आवंटन भाग को फिर से चलाएं (जैसे चरण 1 में) यदि आप परीक्षण चलाने से पहले आवंटित करने के लिए प्रबंधित करते हैं तो बिल्कुल वही स्मृति आवंटित कर सकते हैं, विनाशक ठीक काम करता है।

यह विधि काम करता है (उचित रूप से) जब आपके पास सीमित सीमित स्मृति होती है, अन्यथा यह मेरी राय के लिए कम से कम अनुचित लगता है।

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