बड़े पैमाने पर मॉकिंग के बिना यूनिट परीक्षणों को वास्तव में कैसे लिखा जाना चाहिए?


80

जैसा कि मैं समझता हूं, इकाई परीक्षणों का बिंदु अलगाव में कोड की इकाइयों का परीक्षण करना है । इस का मतलब है कि:

  1. वे कोडबेस में कहीं भी किसी भी असंबंधित कोड परिवर्तन से नहीं टूटना चाहिए ।
  2. इंटीग्रेशन टेस्ट (जो ढेर में टूट सकता है) के विपरीत, केवल एक यूनिट टेस्ट को टेस्टेड यूनिट में बग से टूटना चाहिए।

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

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

अब, प्रश्न (ओं) के लिए।

  1. यूनिट परीक्षणों को कैसे ठीक से लिखा जाना चाहिए?
  2. वास्तव में उनके और एकीकरण परीक्षणों के बीच की रेखा कहां है?

अपडेट १

कृपया निम्नलिखित छद्म कोड पर विचार करें:

class Person {
    constructor(calculator) {}

    calculate(a, b) {
        const sum = this.calculator.add(a, b);

        // do some other stuff with the `sum`
    }
}

क्या एक परीक्षण जो निर्भरता का Person.calculateमजाक उड़ाए बिना विधि का परीक्षण Calculatorकरता है (दिया गया, वह Calculatorएक हल्का वर्ग है जो "बाहरी दुनिया" तक नहीं पहुंचता है) को इकाई परीक्षण माना जा सकता है?


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

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

6
"यह वस्तुतः प्रत्येक इकाई परीक्षण की नकल करने की आवश्यकता है" हाँ, तो? "मॉकिंग के बारे में एक त्वरित Google खोज से कई टन लेखों का पता चलता है जो दावा करते हैं कि" मॉकिंग एक कोड गंध है "" वे गलत हैं
माइकल

13
@ मिचेल ने बस 'हां, हां' का मंचन किया और विरोधी दृष्टिकोण को गलत घोषित करते हुए इस विषय पर एक विवादास्पद विषय का दृष्टिकोण करने का एक शानदार तरीका नहीं है। शायद एक जवाब लिखें और इस बारे में विस्तृत रूप से कहें कि आपको क्यों लगता है कि हर जगह मजाक करना चाहिए, और शायद आपको लगता है कि 'टन के लेख' गलत हैं?
AJFaraday

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

जवाबों:


59

इकाई परीक्षणों का बिंदु अलगाव में कोड की इकाइयों का परीक्षण करना है।

यूनिट टेस्ट में मार्टिन फाउलर

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

केंट बेक ने टेस्ट ड्रिवेन डेवलपमेंट, बाय बाय में लिखा था

मैं उन्हें "इकाई परीक्षण" कहता हूं, लेकिन वे इकाई परीक्षणों की स्वीकृत परिभाषा से बहुत अच्छी तरह मेल नहीं खाते हैं

"यूनिट टेस्ट्स की बात" का कोई भी दावा "यूनिट टेस्ट" की परिभाषा पर बहुत अधिक निर्भर करेगा।

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

आपके द्वारा देखी जाने वाली परस्पर विरोधी सलाह मान्यताओं के एक अलग सेट के तहत काम करने वाले लोगों से आती है।

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

आप तुलना करना चाहते हैं:

क्या एक परीक्षण जो कि कैलकुलेटर पर निर्भरता का मज़ाक उड़ाए बिना व्यक्ति को परीक्षण करने की विधि का परीक्षण कर सकता है (यह देखते हुए, कि कैलकुलेटर एक हल्का वर्ग है जो "बाहरी दुनिया" का उपयोग नहीं करता है) को इकाई परीक्षण माना जा सकता है?

मुझे लगता है कि यह गलत प्रश्न है; यह फिर से लेबल के बारे में एक तर्क है , जब मुझे विश्वास है कि हम वास्तव में क्या परवाह करते हैं, गुण हैं

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

प्रेरक तो Calculator::addकाफी समय परीक्षण चलाने के लिए आवश्यक (या उपयोग के इस मामले में अन्य महत्वपूर्ण विशेषताओं में से किसी) में वृद्धि नहीं करता, तो मैं एक परीक्षण डबल का उपयोग कर परेशान नहीं होगा - यह लाभ है कि लागत पल्ला झुकना प्रदान नहीं करता है ।

यहां दो मान्यताओं पर ध्यान दें: लागत मूल्यांकन के हिस्से के रूप में एक इंसान, और लाभ मूल्यांकन में असत्यापित परिवर्तनों का संक्षिप्त ढेर। उन परिस्थितियों में जहां उन स्थितियों को पकड़ नहीं है, "अलगाव" का मूल्य काफी बदल जाता है।

हैरी पेर्सिवल द्वारा हॉट लावा भी देखें ।


5
एक चीज़ जो मॉकिंग ऐड करती है, वह यह साबित करती है कि कैलकुलेटर का मज़ाक उड़ाया जा सकता है यानी डिज़ाइन में युगल व्यक्ति और कैलकुलेटर नहीं है (हालाँकि इसे अन्य तरीकों से भी जाँचा जा सकता है)
jk।

40

बड़े पैमाने पर मॉकिंग के बिना यूनिट परीक्षणों को वास्तव में कैसे लिखा जाना चाहिए?

अपने कोड में साइड-इफेक्ट्स को कम करके।

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

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

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


8
व्यवहार में और अर्थहीन बहस को चकमा देने के संदर्भ में यह सही उत्तर है।
जेरेड स्मिथ

क्या आपके पास एक गैर-तुच्छ ओपन सोर्स कोडबेस का एक उदाहरण है जो इस तरह की शैली का उपयोग करता है और अभी भी अच्छा परीक्षण कवरेज प्राप्त करता है?
जोएरी सेबर्चेस

4
@JoeriSebrechts हर एक एफपी एक? उदाहरण
जेरेड स्मिथ

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

1
@JoeriSebrechts हम्म, या तो मुझे गलतफहमी है कि आप क्या चाहते हैं, या आपने मेरे द्वारा दिए गए उदाहरण में गहरी खुदाई नहीं की। रैमडा फ़ंक्शन अपने स्रोत (जैसे R.equals) में सभी जगह आंतरिक कॉल का उपयोग करता है । चूँकि ये अधिकांश भाग शुद्ध कार्यों के लिए होते हैं, इसलिए इन्हें आम तौर पर परीक्षणों में शामिल नहीं किया जाता है।
जारेड स्मिथ

31

ये सवाल उनकी कठिनाई में काफी अलग हैं। आइए प्रश्न 2 पहले लें।

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

अब महत्वपूर्ण प्रश्न के लिए: आपको इकाई परीक्षण कैसे करना चाहिए? जैसा कि ऊपर कहा गया है, यूनिट परीक्षणों को केवल आवश्यक रूप से सहायक संरचनाओं का निर्माण करना चाहिए । अक्सर अपने असली डेटाबेस या किसी भी वास्तविक डेटाबेस की तुलना में नकली डेटाबेस का उपयोग करना आसान होता है । हालांकि, अपने आप में मजाक का कोई मूल्य नहीं है। यदि अक्सर ऐसा होता है कि वास्तव में एक मध्य-स्तर इकाई परीक्षण के लिए इनपुट के रूप में किसी अन्य परत के वास्तविक घटकों का उपयोग करना आसान होता है । यदि हां, तो उनका उपयोग करने में संकोच न करें।

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

इसलिए, मज़ाक करने का धर्म मत बनाओ। यह एक साधन है, अंत नहीं है, इसलिए यदि आप अतिरिक्त प्रयास से बचने के साथ दूर हो सकते हैं, तो आपको ऐसा करना चाहिए।


4
The only critical problem would be if a defect triggered too few failures.यह मॉकिंग के कमजोर बिंदुओं में से एक है। हमें अपेक्षित व्यवहार को "प्रोग्राम" करना होगा, इसलिए हम ऐसा करने में विफल हो सकते हैं, जिससे हमारे परीक्षण "झूठे सकारात्मक" के रूप में समाप्त हो जाएंगे। लेकिन नियतिवाद (परीक्षण की सबसे महत्वपूर्ण शर्त) को प्राप्त करने के लिए मॉकिंग एक बहुत ही उपयोगी तकनीक है। मैं अपने सभी प्रोजेक्ट्स में उनका उपयोग संभव होने पर करता हूं। वे मुझे भी दिखाते हैं जब एकीकरण बहुत जटिल है या निर्भरता बहुत तंग है।
लाईव

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

11
@AlexanderLomia: आप एक इकाई को क्या कहेंगे? क्या आप 'स्ट्रिंग' को एक इकाई भी कहेंगे? मैं करूंगा, लेकिन मैं इसका मजाक उड़ाने का सपना नहीं देखूंगा।
बार्ट वैन इनगेन शेनौ

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

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

6

ठीक है, तो सीधे आपके सवालों का जवाब देने के लिए:

यूनिट परीक्षणों को कैसे ठीक से लिखा जाना चाहिए?

जैसा कि आप कहते हैं, आपको निर्भरता का परीक्षण करना चाहिए और प्रश्न में केवल इकाई का परीक्षण करना चाहिए।

वास्तव में उनके और एकीकरण परीक्षणों के बीच की रेखा कहां है?

एक एकीकरण परीक्षण एक इकाई परीक्षण है जहां आपकी निर्भरता का मज़ाक नहीं उड़ाया जाता है।

क्या कैलकुलेटर का मज़ाक उड़ाए बिना पर्सनलाइकलेट पद्धति का परीक्षण करने वाला परीक्षण एक इकाई परीक्षण माना जा सकता है?

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

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

लेकिन आपका असली सवाल यह है:

मॉकिंग के बारे में एक त्वरित Google खोज ने कई लेखों का खुलासा किया है जो दावा करते हैं कि "मॉकिंग एक कोड गंध है" और ज्यादातर (हालांकि पूरी तरह से नहीं) से बचा जाना चाहिए।

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

public class MockCalc : ICalculator
{
     public Add(int a, int b) { return 4; }
}

मैं ऐसा कुछ नहीं करूंगा:

myMock = Mock<ICalculator>().Add((a,b) => {return a + b;})
myPerson.Calculate()
Assert.WasCalled(myMock.Add());

मैं यह तर्क दूंगा कि, "मेरे मॉक का परीक्षण करना" या "कार्यान्वयन का परीक्षण करना" होगा। मैं कहूंगा " मत लिखो मत! * उस तरह"।

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


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

कोई संभावना नहीं है, मुझे लगता है कि समस्या यह है कि दो चीजों की परिभाषा हर किसी के द्वारा 100% सहमत नहीं हैं।
इवान

मैं आपकी कक्षा MockCalcका नाम बदल दूंगा StubCalc, और इसे ठूंठ नहीं मॉक कहूंगा। martinfowler.com/articles/…
bdsl

@bdsl यह लेख 15 साल पुराना है
ईवान

4
  1. यूनिट परीक्षणों को ठीक से कैसे लागू किया जाना चाहिए?

अंगूठे का मेरा नियम है कि उचित इकाई परीक्षण:

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

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

  1. वास्तव में उनके बीच की रेखा [इकाई परीक्षण] और एकीकरण परीक्षण कहां झूठ बोलते हैं?

मैंने इस भेद को सबसे उपयोगी पाया है:

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

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

  1. क्या यह सच है कि वस्तुतः प्रत्येक इकाई परीक्षण का मजाक उड़ाना जरूरी है?

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

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

परीक्षण इकाई में बग द्वारा केवल एक इकाई परीक्षण को तोड़ना चाहिए।

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


3
  1. वे कोडबेस में कहीं भी किसी भी असंबंधित कोड परिवर्तन से नहीं टूटना चाहिए ।

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

  1. इंटीग्रेशन टेस्ट (जो ढेर में टूट सकता है) के विपरीत, केवल एक यूनिट टेस्ट को टेस्टेड यूनिट में बग से टूटना चाहिए।

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

वास्तव में उनके और एकीकरण परीक्षणों के बीच की रेखा कहां है?

मुझे नहीं लगता कि यह एक महत्वपूर्ण अंतर है। किसी भी तरह कोड की 'इकाई' क्या है?

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

बड़े पैमाने पर मॉकिंग के बिना यूनिट परीक्षणों को वास्तव में कैसे लिखा जाना चाहिए?

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


" किसी भी तरह से कोड की एक 'इकाई' क्या है? बहुत अच्छा सवाल है कि अप्रत्याशित जवाब हो सकते हैं जो इस बात पर भी निर्भर हो सकता है कि कौन उत्तर दे रहा है। आमतौर पर, यूनिट परीक्षणों की अधिकांश परिभाषाएं उन्हें एक विधि या एक वर्ग से संबंधित के रूप में समझाती हैं लेकिन यह सभी मामलों में "यूनिट" का वास्तव में उपयोगी उपाय नहीं है। अगर मेरे पास एक Person:tellStory()विधि है जो किसी व्यक्ति के विवरण को एक स्ट्रिंग में शामिल करता है तो वह वापस लौटता है, तो "कहानी" शायद एक इकाई है। यदि मैं एक निजी सहायक विधि बनाता हूं जो कुछ कोड को दूर करता है, तो मुझे विश्वास नहीं होता कि मैंने एक नई इकाई शुरू की है - मुझे अलग से परीक्षण करने की आवश्यकता नहीं है।
व्लाज

1

सबसे पहले, कुछ परिभाषाएँ:

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

उस परिभाषा के तहत, मुझे शुद्ध कार्यों की नकल करने के लिए एक सम्मोहक कारण दिखाई नहीं देता है, जिसका अर्थ है कि इकाई परीक्षण खुद को शुद्ध कार्यों, या बिना दुष्प्रभावों के कार्यों के लिए उधार देता है।

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

कोड बदबू आ रही है

इसके लिए, हम विकिपीडिया का रुख करेंगे:

कंप्यूटर प्रोग्रामिंग में, एक कोड गंध एक प्रोग्राम के स्रोत कोड में कोई विशेषता है जो संभवतः एक गहरी समस्या को इंगित करता है।

यह बाद में भी जारी है ...

"गंध कोड में कुछ संरचनाएं हैं जो मौलिक डिजाइन सिद्धांतों के उल्लंघन और डिजाइन की गुणवत्ता को नकारात्मक रूप से प्रभावित करती हैं"। सूर्यनारायण, गिरीश (नवंबर 2014)। सॉफ्टवेयर डिजाइन की बदबू आ रही है। मॉर्गन कॉफ़मैन। पी। 258।

कोड की गंध आमतौर पर कीड़े नहीं हैं; वे तकनीकी रूप से गलत नहीं हैं और कार्यक्रम को कार्य करने से नहीं रोकते हैं। इसके बजाय, वे डिजाइन में कमजोरियों को इंगित करते हैं जो विकास को धीमा कर सकते हैं या भविष्य में बग या विफलताओं के जोखिम को बढ़ा सकते हैं।

दूसरे शब्दों में, सभी कोड बदबू खराब नहीं होते हैं। इसके बजाय, वे सामान्य संकेत हैं कि कुछ अपने इष्टतम रूप में व्यक्त नहीं किया जा सकता है, और गंध प्रश्न में कोड को बेहतर बनाने का अवसर दिखा सकता है।

मॉकिंग के मामले में, गंध इंगित करता है कि जो इकाइयाँ मॉक के लिए बुला रही हैं, वे मॉक होने वाली इकाइयों पर निर्भर करती हैं । यह एक संकेत हो सकता है कि हमने समस्या को परमाणु-सॉल्व करने योग्य टुकड़ों में विघटित नहीं किया है, और यह सॉफ़्टवेयर में डिज़ाइन दोष का संकेत दे सकता है।

सभी सॉफ्टवेयर डेवलपमेंट का सार एक बड़ी समस्या को छोटे, स्वतंत्र टुकड़ों (अपघटन) में तोड़ने और समाधान को एक साथ मिलकर एक एप्लिकेशन बनाने के लिए होता है जो बड़ी समस्या (रचना) को हल करता है।

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

एक कोड गंध का मजाक उड़ाने से क्या होता है कि नकली के साथ कुछ गलत नहीं है - कभी-कभी यह बहुत उपयोगी होता है। क्या यह एक कोड गंध बनाता है कि यह आपके आवेदन में युग्मन के एक समस्याग्रस्त स्रोत का संकेत दे सकता है। कभी-कभी युग्मन के उस स्रोत को हटाने से नकली लिखना अधिक उत्पादक होता है।

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


0

इकाई परीक्षणों में भी मॉकिंग का उपयोग केवल अंतिम उपाय के रूप में किया जाना चाहिए।

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

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

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

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

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