2009-08-03 14 views
8

मान लीजिए आप एक विधि है:इकाई परीक्षण (हाँ या नहीं)

public void Save(Entity data) 
{ 
    this.repositoryIocInstance.EntitySave(data); 
} 

आप बिल्कुल एक इकाई परीक्षण लिखने चाहेंगे?

public void TestSave() 
{ 
    // arrange 
    Mock<EntityRepository> repo = new Mock<EntityRepository>(); 
    repo.Setup(m => m.EntitySave(It.IsAny<Entity>()); 

    // act 
    MyClass c = new MyClass(repo.Object); 
    c.Save(new Entity()); 

    // assert 
    repo.Verify(m => EntitySave(It.IsAny<Entity>()), Times.Once()); 
} 

बाद में यदि आप ऐसा करने के लिए परिवर्तन विधि के कार्यान्वयन करना क्योंकि अधिक "जटिल" सामान की तरह:

public void Save(Entity data) 
{ 
    if (this.repositoryIocInstance.Exists(data)) 
    { 
     this.repositoryIocInstance.Update(data); 
    } 
    else 
    { 
     this.repositoryIocInstance.Create(data); 
    } 
} 

... अपने इकाई परीक्षण विफल हो जाएगा लेकिन यह शायद आपके आवेदन को तोड़ने नहीं होगा ...

प्रश्न

मैं भी तरीकों पर इकाई परीक्षण बनाने के लिए परेशान करना चाहिए कि में कोई वापसी प्रकार नहीं है * या ** आंतरिक नकली के बाहर कुछ भी नहीं बदलते हैं?

उत्तर

2

यह सच है कि आपका परीक्षण आपके कार्यान्वयन के आधार पर है, जो कुछ आपको टालना चाहिए (हालांकि यह वास्तव में कभी-कभी इतना आसान नहीं है ...) और यह आवश्यक नहीं है। लेकिन इस तरह के परीक्षणों को तोड़ने की उम्मीद है भले ही आपका परिवर्तन कोड को तोड़ न दे।

आप इस के लिए कई दृष्टिकोण हो सकता है: के रूप में उम्मीद

  • एक परीक्षण है कि वास्तव में डेटाबेस के लिए चला जाता बनाएं और देखें कि क्या राज्य में बदल गया था (यह नहीं एक इकाई परीक्षण अब हो जाएगा)
  • एक परीक्षण ऑब्जेक्ट बनाएं जो डेटाबेस को बनाता है और मेमोरी इन-मेमोरी (आपके रिपॉजिटरी IocInstance के लिए एक और कार्यान्वयन) करता है, और सत्यापित करता है कि राज्य अपेक्षित के रूप में बदला गया था। रिपोजिटरी इंटरफ़ेस में परिवर्तन इस ऑब्जेक्ट में भी बदलावों में होंगे। लेकिन आपके इंटरफेस ज्यादा नहीं बदलना चाहिए, है ना?
  • इस रूप में भी महंगा के सभी देखते हैं, और अपने दृष्टिकोण का उपयोग करें, जो अनावश्यक रूप से बाद में परीक्षण को तोड़ने पर देनी पड़ सकती है जब वहाँ isn '
+0

आपका उत्तर अब तक के सबसे नज़दीक है जो मैं जानना चाहता था। लेकिन आप इस मामले में दूसरी गोली बुलेट रिपोजिटरी करेंगे और विधि नहीं, है ना? –

+0

मुझे ऐसा नहीं लगता है। यह एक ऑब्जेक्ट हो सकता है जिसमें एक सूची (या शायद एक सेट, जो आप चाहते हैं उस पर निर्भर करता है) और "EntitySave" केवल इकाई को जोड़ देगा (यदि मौजूद है? मुझे नहीं पता कि यह कैसे काम करना चाहिए)। एकाधिक तालिकाओं में शामिल नहीं हो रहा है, या आपके भंडार की अन्य जटिल सामग्री नहीं हो सकती है। –

+0

आपका ऑब्जेक्ट कार्यान्वयन अधिक महंगा होगा, जैसा कि उल्लेख किया गया है, लेकिन आईएमएचओ यह देखने का सबसे अच्छा तरीका है कि कॉल लगातार तरीके से किया गया था या नहीं। –

1

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

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

+0

इस मामले में, इस विधि को यूनिट को तोड़ने के बाद यूनिट परीक्षण की आवश्यकता नहीं है, टेस्ट ब्रेक करें। मैं इस मामले में नकल का परीक्षण कर रहा हूं, न कि अनुबंध जो विधि के दायरे में मौजूद नहीं है। –

1

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

+0

इकाई परीक्षण के भीतर नया राज्य पूरी तरह से नकली पर निर्भर करता है ... यही कारण है कि मेरे पास दूसरे विचार हैं। यदि मेरी सभी पद्धतियां भंडार में कॉल करती हैं और एक परीक्षण के भीतर मजाक किया जाता है तो इसका वास्तविक परिणाम वास्तविक जीवन की स्थिति के आधार पर अनुमानित परिणाम नहीं होगा। यह हमेशा पास होगा। –

+0

आपको नकली परीक्षण नहीं करना चाहिए, बल्कि ऑपरेशन जो नकली के साथ बातचीत करता है। मान लें, आपके पास एक वस्तु 'एक्स' है जिसमें एक विधि 'एम()' है जो भंडार को कॉल करती है। आप यह जांचना चाहते हैं कि रिपॉजिटरी को कॉल वास्तव में बनाया गया है, इसलिए आप रिपोजिटरी का एक मॉक लिखते हैं, फिर अपनी 'एक्स.एम()' विधि को कॉल करें। परीक्षण को नकली में बदलाव करना चाहिए, जो साबित करेगा कि आपकी विधि 'एम() 'आवश्यकतानुसार काम करती है। जब आपके पास भंडार का वास्तविक कार्यान्वयन होता है, तो आप उस कार्यान्वयन का परीक्षण करते हैं (नकली नहीं) - तब आप भंडार का परीक्षण करेंगे। –

+0

@jeyoung: लेकिन यह एक अलग इकाई परीक्षण है। यह भंडार का एक यूनिट परीक्षण है जो वर्ग नहीं है जो उपरोक्त कोड के अनुसार भंडार को कॉल करता है ... लेकिन हाँ। बात यह है कि मैं डीएएल का परीक्षण नहीं करता क्योंकि यह जेनरेट कोड है। और काम करने की उम्मीद है जैसा कि इसे करना चाहिए। और मैं इकाई परीक्षण करने का इरादा नहीं रखता हूं। –

1

"अपने इकाई परीक्षण विफल हो जाएगा लेकिन यह शायद आपके आवेदन को तोड़ने नहीं होता"

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

चाल प्राथमिकता देना है।

पहले महत्वपूर्ण सामग्री का परीक्षण करें। जब चीजें धीमी होती हैं, तो छोटी चीजों के लिए परीक्षण जोड़ें।

+0

आप अंतिम वाक्य में सही हो सकते हैं (इसके लिए +1)। यहां मुख्य समस्या यह है कि परीक्षण अमान्य हो जाएगा, कोड नहीं, जो एक बेहतर संस्करण में विकसित होगा। –

6

यह न भूलें कि यूनिट परीक्षण केवल परीक्षण कोड के बारे में नहीं है। यह निर्धारित करने की अनुमति देने के बारे में है जब व्यवहार बदलता है।

तो आपके पास कुछ ऐसा हो सकता है जो तुच्छ है। हालांकि, आपका कार्यान्वयन बदलता है और आपके पास दुष्प्रभाव हो सकता है। आप अपने रिग्रेशन टेस्ट सूट को बताने के लिए चाहते हैं।

उदा। अक्सर लोग कहते हैं कि आपको सेटर्स/गेटर्स का परीक्षण नहीं करना चाहिए क्योंकि वे छोटे हैं। मैं असहमत हूं, क्योंकि वे जटिल तरीके हैं, लेकिन कोई अनजाने में अज्ञानता, वसा-उंगली परिदृश्य इत्यादि के माध्यम से उन्हें बदल सकता है

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

+0

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

+0

मैं कहूंगा कि 'रिग्रेशन' दोनों इकाई और एकीकरण को कवर करता है - यह इंगित करता है कि वे लगातार चलते हैं (हर निर्माण पर कहते हैं)।स्वचालित रूप से जेनरेट किए गए कोड का परीक्षण करने के लिए, मुझे लगता है कि यह एक ऐसा निर्णय है जो पीढ़ी की प्रक्रिया में आपके विश्वास के आधार पर किसी भी तरह से जा सकता है, यह कितना जटिल है आदि। –

1

(लेकिन एक बार सम्भावना कम होती है, यह ठीक जोखिम लेने के लिए है) एक विधि में एक दावा, आप अनिवार्य रूप से जोर दे रहे हैं कि अपवाद फेंक नहीं रहे हैं।

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

public void myMethod() 

अपने प्रश्न का

public ComplexObject myMethod() { 
DoLotsOfSideEffects() 
return new ComplexObject { rows changed, primary key, value of each column, etc }; 
} 

और नहीं

public bool myMethod() 
    DoLotsOfSideEffects() 
    return true; 
+0

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

+0

@jeyoung: अगर मैं आपको सही ढंग से समझता हूं, तो इस तरह के परीक्षण यूनिट परीक्षण से परे जाते हैं ... वे परीक्षण की जा रही इकाई से गहरे जाते हैं, है ना? –

+0

@jeyoung। आप "सार्वजनिक शून्य बचत पंक्ति()" का परीक्षण करने के लिए कह रहे हैं, आपको "सार्वजनिक डेटारो लोडरो()" का आह्वान करना होगा? – MatthewMartin

2

संक्षिप्त उत्तर हो जाता है: हाँ, आपको चाहिए कि तरह निश्चित रूप से परीक्षण तरीकों।

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

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

आपकी विधि में, आप कह सकते हैं कि उस रेखा को हटाने वाले किसी भी व्यक्ति को ऐसा करना होगा अगर उनके पास घातक इरादे हैं, लेकिन बात यह है: सरल चीजें डॉन ' जरूरी नहीं कि सरल रहें, और जटिल होने से पहले आप इकाई परीक्षणों को बेहतर ढंग से लिखते हैं।

यह एक कार्यान्वयन विस्तार है कि सेव विधि रिपोजिटरी पर एंटीटीसेव को आमंत्रित करती है - यह अपेक्षित व्यवहार का हिस्सा है, और एक महत्वपूर्ण महत्वपूर्ण हिस्सा है, अगर मैं ऐसा कहूं। आप यह सुनिश्चित करना चाहते हैं कि डेटा वास्तव में सहेजा जा रहा है।

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

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

यह परीक्षण Inderect आउटपुट कहा जाता है, और अधिक सामान्य प्रत्यक्ष आउटपुट (वापसी मान) के बजाय।

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

यह सब, और बहुत कुछ, उत्कृष्ट xUnit Test Patterns में समझाया गया है।

+0

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

+0

@ रॉबर्ट कोरिटनिक: मुझे लगता है कि पहली बार किसी ने दावा किया था कि मुझे इकाई परीक्षण और टेस्ट डबल्स नहीं समझते हैं ... मैं सहमत हूं कि यदि कोई विधि * केवल * आंतरिक * स्थिति बदलती है, तो यूनिट लिखने का कोई कारण नहीं है इसके लिए परीक्षण करें, लेकिन फिर, इस तरह के कोड के लिए क्या कारण होगा? हो सकता है कि मैं आपके प्रश्न से निष्कर्ष निकाला हो, लेकिन मुझे लगता है कि प्रश्न में सदस्य चर एक रिपोजिटरी का प्रतिनिधित्व करता है, और एक रिपोजिटरी मेरी पुस्तक में * बाहरी * राज्य का प्रतिनिधित्व करता है। –

+2

>> यदि आप इसके लिए यूनिट परीक्षण नहीं लिखते हैं, तो आप कैसे जानते हैं? << कोड को देखकर तुच्छ है? अन्यथा कोई भी यह सुनिश्चित नहीं कर सकता कि परीक्षण सही है - परीक्षण के तहत कोड को और अधिक जटिल लग रहा है। – KolA

3

अपने आप से दो प्रश्न पूछें। "इस इकाई परीक्षण के मैनुअल समतुल्य क्या है?" और "क्या यह स्वचालित है?"। आपके मामले में यह कुछ ऐसा होगा:

मैन्युअल समतुल्य क्या है? - अगले में कदम है, सुनिश्चित करें कि आप IRepository.EntitySave कार्यान्वयन के अंदर कर रहे हैं

यह स्वचालित लायक है बनाने - "सहेजें" विधि में कदम - डिबगर शुरू? मेरा जवाब "नहीं" है। यह कोड से 100% स्पष्ट है। सैकड़ों समान अपशिष्ट परीक्षणों से मुझे एक ऐसा नहीं देखा जो उपयोगी साबित होगा।

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