2009-07-16 17 views
6

में टेस्ट सीम छिपाने के लिए सर्वोत्तम अभ्यास मैं यूनिट-परीक्षण के लिए कुछ सलाह ढूंढ रहा हूं जो उत्पादन कोड में "टेस्ट हुक" नहीं छोड़ता है।.NET यूनिट परीक्षण - रिलीज कोड

मान लीजिए कि मेरे पास एक स्थाई वर्ग (वीबी.नेट मॉड्यूल) है जिसका नाम विधिLogger है, जिसमें "शून्य लिखेंइन्ट्री (स्ट्रिंग संदेश)" विधि है जो कॉलिंग विधि और डिस्क पर लॉग फ़ाइल को संदेश लिखने का इरादा है। WriteEntry() का वास्तविक लक्ष्य यूनिट परीक्षण चलाने के लिए IMethodLogger के नकली कार्यान्वयन में बदल दिया जा सकता है, और सभी अन्य मामलों में इसे IMethodLogger के वास्तविक कार्यान्वयन को कॉल करना चाहिए।

यहाँ मैं क्या हो रहा कोसा गया है अब तक का एक मोटा-कट है, और मैं दृष्टिकोण की तरह है - लेकिन कुछ त्वरित परीक्षण में यह कुछ सवाल और संदेह को जन्म देती है:

[InternalAttributesVisibleTo("MethodLogger.Tests")] 
internal static class MethodLogger 
{ 
    public void WriteEntry(string message) 
    { 
     LogWriter.WriteEntry(message); 
    } 

    private IMethodLogger LogWriter 
    { 
     get; 
     set; 
    } 

#if DEBUG 
    internal void SetLogWriter(IMethodLogger logger) 
    { 
     LogWriter = logger; 
    } 
#endif 
} 

यहाँ मेरी विशिष्ट प्रश्न है:

  • यह कसकर युगल परीक्षण DEBUG निर्माण के खिलाफ चलने के लिए जोड़ता है; जब मैं इकाई परीक्षण चलाता हूं हालांकि ऐसा लगता है कि यह विशेष रूप से डेब्यूग में परीक्षण के तहत असेंबली का पुनर्निर्माण नहीं करता है - क्या ऐसा करना संभव है?

    • क्या मैं कभी भी एक गैर-डीबग बिल्ड के खिलाफ यूनिट परीक्षण चलाने के लिए चाहता हूं? मेरे सिर के ऊपर से मुझे कम मूल्य दिखाई देता है - लेकिन क्या होगा?
  • क्या मेरे लिए "डेबग" के बदले "पूर्व" जैसे कस्टम प्री-कंपाइलर ध्वज का उपयोग करना संभव होगा? मैं विजुअल स्टूडियो को के साथ हमेशा के साथ इस झंडे को फिर से बनाने के बारे में बताऊंगा कि यह सुनिश्चित करने के लिए कि मेरे हुक/सीम उपलब्ध हैं?

+0

क्या आपने इसके लिए एओपी ढांचा माना है? पोस्टशर्प –

+0

@ क्रिस एस: नहीं, यह वास्तव में मेरे लिए एक नया संक्षेप है - परिभाषाओं की एक त्वरित नज़र मुझे थोड़ा आईओसी (जो मैं भी बहुत हरा हूं) सोचता हूं। दोनों के बीच कोई विशेष भेद या मतभेद? – STW

उत्तर

3

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

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

हालांकि, आपकी वास्तविक प्रश्नों का उत्तर देने:

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

आपने मुझे कॉल करने से किसी भी मेरे साथियों (एक को छोड़कर) को रोकने के लिए एक साधारण आईडीई चेतावनी के विचार पर मुझे छेड़छाड़ की। मैं खराब कोड और कुछ मेहनती लोगों से भरे गंदे स्थान पर हूं, जॉन ... – STW

4

हम तो, हाँ, मुझे लगता है कि उन्हें काम करने के लिए मूल्य है बनाता है, क्योंकि हम अक्सर खुला समस्याओं इस तरह से है रिलीज/अस्पष्ट के खिलाफ परीक्षण चलाने के लिए सुनिश्चित करें,।

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

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

2

#IF DEBUG आदि होने के कारण ... खराब फॉर्म है।

उत्पादन कोड परीक्षण/डीबग कोड से स्वतंत्र होना चाहिए।

मैं इकाई परीक्षण में सहायता के लिए निर्भरता इंजेक्शन की तलाश करने की सलाह दूंगा।

+1

#IF एक प्रीप्रोसेसर निर्देश है जो संकलन से पहले होता है। अगर स्थिति पूरी नहीं हुई है, तो वह कोड आईएल में खत्म नहीं होगा। –

+1

यह बात नहीं है। यह अभी भी एक ही स्रोत फ़ाइल में आपके उत्पादन कोड के रूप में है जो कि गलत है। – Finglas

+2

मुझे लगता है कि डॉकर्स जानता है कि #if DEBUG * है * ... वह सिर्फ यह कह रहा है कि यह एक अच्छा विचार नहीं है और आमतौर पर कोड गंध इंगित करता है। वह सही है, आईएमओ। – Randolpho

1

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

हुक छोड़ने में कुछ भी गलत नहीं है - वास्तव में, आप विधि सार्वजनिक विधि बनाने और किसी भी कोड को लॉगिंग हुक बदलने की अनुमति दे सकते हैं।

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

मैं इसे जगह में हुक छोड़ने के लिए ठीक किया जा रहा है, को दूर करने में यह सिर्फ एक प्राथमिकता है, लेकिन मैं इसे सार्वजनिक करने से सहमत नहीं देख सकते हैं - यह बहुत अधिक अनुमतियों को ऊपर उठाने सिर्फ इसलिए कि उसे निकाल देता है की तरह लगता है थोड़ा परेशानी - योउडर

ठीक है, मैं सामान्य कोड संगठन सिद्धांतों पर अधिक टिप्पणी कर रहा था। आमतौर पर आपके कोड के लिए ऐसे हुक बनाने का एक अच्छा विचार है; आपके मामले में आप "परेशानी को दूर करने के लिए अनुमतियों को बढ़ाने" नहीं होंगे, आप "एक मजबूत और लचीला लॉगिंग फ्रेमवर्क तैयार करेंगे"।

+0

मैं इसे हुक छोड़ने के लिए ठीक कह सकता हूं, इसे हटाने का सिर्फ एक प्राथमिकता है, लेकिन मैं इसे सार्वजनिक करने के लिए सहमत नहीं हूं - यह अनुमतियों को बढ़ाने की तरह बहुत अधिक महसूस करता है क्योंकि यह थोड़ा परेशानी को दूर करता है। – STW

1

यह मेरे लिए एक आईओसी कंटेनर के लिए एक प्रमुख उम्मीदवार की तरह लगता है। मैं अपना लॉगर स्थिर नहीं बनाऊंगा, और परीक्षण, विकास और उत्पादन के लिए अलग-अलग विन्यास स्थापित करता हूं।

1

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

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

आईएमओ सेटलॉगवाइटर के साथ पूरा करने का प्रयास करने का सबसे अच्छा तरीका है वास्तव में विभिन्न कॉन्फ़िगरेशन के आधार पर रनटाइम पर कंक्रीट को असाइन करने के लिए StructureMap जैसे नियंत्रण कंटेनर का एक उलटा उपयोग करना है। यूनिट परीक्षण समय के दौरान आप Moq जैसे लाइब्रेरी का उपयोग कर सकते हैं जो कि अपेक्षित तरीके से व्यवहार करने वाले कंक्रीट बनाने के लिए (एक SQL क्वेरी जो हमेशा एक ही सटीक परिणाम देता है) हालांकि आपके विशेष मामले में आप केवल विपरीत प्रदर्शन कर रहे हैं (इकाई परीक्षण बनाम वांछित लॉगिंग उत्पादन रन समय पर कोई लॉगिंग नहीं)।

+0

मेरे लिए कुछ अच्छे लीड देखने के लिए। दुर्भाग्य से इस विशेष मामले के लिए विधिLogger वास्तव में पहले से ही सभी tarnation उपयोग में लागू किया गया है ... – STW

2

माइकल फेदर के अनुसार "विरासत संहिता के साथ प्रभावी ढंग से कार्य करना" पुस्तक के मुताबिक ऐसा लगता है कि अगर आप सेटर को परीक्षण के लिए कुछ विशिष्ट नाम देते हैं तो यह बेहतर होगा।

उदाहरण: SetTestingLogger (IMethodLogger लकड़हारा)

मैं भी पूर्वप्रक्रमक बयान को दूर करेंगे।किताब में यह भी कहा है और मैं बोली

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

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

पुस्तक में "स्टेटस सेटर परिचय" अनुभाग अधिक विस्तार से बताता है। मैं इसे प्रत्येक डेवलपर्स के पास एक पुस्तक के रूप में अनुशंसा करता हूं।

+0

मुझे गैर अस्पष्ट आत्म-वर्णन कोड पसंद है :) – STW

+0

पंखों के लिए +1! महान किताब! – TrueWill

4

हकीकत में, आप निर्भरता इंजेक्शन की ओर सड़क पर कर रहे हैं - आप बस अभी तक यह महसूस नहीं किया है :)

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

मैंने इस बारे में बहुत पहले Testability Is Really The Open/Closed Principle में लिखा था।

  1. यह एक उदाहरण वर्ग के बजाय एक स्थिर वर्ग बनाओ:

    अपने विशिष्ट मामले में, परिवर्तन की एक जोड़ी आप MethodLogger वर्ग के लिए करना चाहिए रहे हैं। चूंकि सभी अनुभवी टीडीडी प्रैक्शनर्स आपको बताएंगे, स्टेटिक्स बुरा हैं।

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

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

+0

@STW - डीआई कंटेनर (फ्रेमवर्क) के मार्क का सुझाव आपको इसे एक इंस्टेंस क्लास में बदलने देगा, लेकिन (वैकल्पिक रूप से) प्रत्येक उपभोक्ता को एक ही उदाहरण प्रदान करेगा। – TrueWill

0

यह मुझे "डीबग" के एवज में "टेस्ट" की तरह एक कस्टम पूर्व संकलक ध्वज का उपयोग करने के लिए संभव होगा? मैं पर विज़ुअल स्टूडियो को हमेशा पर परीक्षण के लिए इस ध्वज के साथ लक्ष्य को पुनर्निर्माण के बारे में बताऊंगा ताकि यह सुनिश्चित किया जा सके कि मेरे हुक/सीम उपलब्ध हैं?

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

2
  1. अन्य लोगों की तरह कहा है, निर्भरता इंजेक्शन और उलट-ऑफ-द नियंत्रण (आईओसी) की ओर ले जाने
  2. अच्छी तरह से कक्षाओं-अंडर-परीक्षण को अलग, (आदि अलगाव चौखटे की मदद Moq, साथ)
  3. एक अलग विधानसभा में कदम परीक्षण - #if डीबग की कोई आवश्यकता नहीं ... #endif
4

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

http://blog.typemock.com/2009/01/isolator-new-vbnet-friendly-api.html

(भी, यह केवल है एक वीबी अनुकूल एपीआई के साथ उपकरण)

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