2012-09-21 33 views
151

मैं 3 प्रयोजनों के लिए JUnit परीक्षण मामलों लिखें:Mockito.verify() का उपयोग कब करें?

  1. कि मेरे कोड सभी के तहत आवश्यक कार्यक्षमता के सभी, को संतुष्ट करता है सुनिश्चित करने के लिए (या के सबसे) इनपुट संयोजन/मूल्यों।
  2. यह सुनिश्चित करने के लिए कि मैं कार्यान्वयन को बदल सकता हूं, और मुझे यह बताने के लिए जुनीट परीक्षण मामलों पर भरोसा करता हूं कि मेरी सभी कार्यक्षमता अभी भी संतुष्ट है।
  3. सभी उपयोग मामलों के दस्तावेज़ीकरण के रूप में मेरा कोड संभालता है, और रीफैक्टरिंग के लिए एक spec के रूप में कार्य करता है - क्या कोड को फिर से लिखना आवश्यक है। (कोड को दोबारा दोहराएं, और यदि मेरे जुनीट परीक्षण विफल हो जाते हैं - तो शायद आप कुछ उपयोग मामले को याद करते हैं)।

मुझे समझ में नहीं आता कि Mockito.verify() का उपयोग क्यों किया जाना चाहिए। जब मुझे verify() कहा जाता है, तो यह मुझे बता रहा है कि मेरा जुनीट कार्यान्वयन के बारे में जागरूक हो रहा है। (इस प्रकार मेरा कार्यान्वयन बदलना मेरे junits तोड़ देगा, भले ही मेरी कार्यक्षमता अप्रभावित थी)।

  1. क्या Mockito.verify() का उचित उपयोग करने के लिए दिशा निर्देश होना चाहिए:

    मैं तलाश कर रहा हूँ?

  2. क्या यह मूल रूप से परीक्षण के तहत वर्ग के कार्यान्वयन के बारे में जागरूक होने के लिए जुड़ा हुआ है या कसकर जुड़ा हुआ है?

+0

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

उत्तर

58

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

इसका तात्पर्य है कि कक्षा ए के अनुबंध में पर्याप्त विवरण है कि यह प्रकार सी (जो एक इंटरफ़ेस या कक्षा हो सकता है) के बारे में बात करता है। तो हाँ, हम विनिर्देश के एक स्तर के बारे में बात कर रहे हैं जो केवल "सिस्टम आवश्यकताएं" से परे है, और कार्यान्वयन का वर्णन करने के लिए कुछ रास्ता तय करता है।

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

अद्यतन:

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

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

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

+3

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

+0

@Russell भले ही "टाइप सी" लाइब्रेरी के चारों ओर एक रैपर के लिए एक इंटरफेस है, या आपके आवेदन के कुछ अलग उपप्रणाली के आसपास है? –

+1

मैं यह नहीं कहूंगा कि यह कुछ सब सिस्टम या सेवा को लागू करने के लिए पूरी तरह से बेकार है-बस इसके आसपास कुछ दिशानिर्देश होना चाहिए (उन्हें बनाना जो मैं करना चाहता था)। पूर्व के लिए: (शायद मैं इसे अधिक आसानी से कर रहा हूं) कहें, मैं अपने कोड में StrUtil.equals() का उपयोग कर रहा हूं, और कार्यान्वयन में StrUtil.equalsIgnoreCase() पर स्विच करने का निर्णय लेता हूं। अगर जुनीट ने सत्यापित किया था (स्ट्रूट। बराबर), मेरा परीक्षण विफल हो सकता है हालांकि कार्यान्वयन सटीक है। यह सत्यापित कॉल, आईएमओ, खराब अभ्यास है हालांकि यह पुस्तकालयों/उप-प्रणालियों के लिए है। दूसरी तरफ, बंद करने के लिए कॉल सुनिश्चित करने के लिए सत्यापित करें डीबीकॉन वैध उपयोगकेस हो सकता है। – Russell

46

डेविड का जवाब बिल्कुल सही है लेकिन यह स्पष्ट नहीं करता कि आप यह क्यों चाहते हैं।

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

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

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

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

+0

+1 अधिक पूर्ण स्पष्टीकरण – CodyBugstein

21

यह एक अच्छा सवाल है! मुझे लगता है कि इसका मूल कारण निम्नलिखित है, हम न केवल यूनिट परीक्षण के लिए जुनीट का उपयोग कर रहे हैं। तो सवाल यह ऊपर splited किया जाना चाहिए:

  • मैं अपने एकीकरण (या किसी अन्य उच्च-से-इकाई परीक्षण) परीक्षण में Mockito.verify() का उपयोग करना चाहिए?
  • क्या मुझे अपने ब्लैक-बॉक्स यूनिट-परीक्षण में Mockito.verify() का उपयोग करना चाहिए?
  • क्या मुझे अपने व्हाइट-बॉक्स यूनिट-परीक्षण में Mockito.verify() का उपयोग करना चाहिए?

इसलिए यदि हम उच्च-से-इकाई परीक्षण पर ध्यान नहीं देगा, सवाल "rephrased जा सकता है का उपयोग व्हाइट बॉक्स Mockito.verify() के साथ इकाई परीक्षण इकाई परीक्षण के बीच महान जोड़ी बनाता है और मेरी कार्यान्वयन कर सकता , क्या मैं कुछ "ग्रे-बॉक्स" यूनिट-परीक्षण कर सकता हूं और अंगूठे के नियमों का उपयोग इस के लिए करना चाहिए "।

अब, चलिए इस चरण-दर-चरण से गुजरते हैं।

* - मैं अपने एकीकरण (या किसी अन्य उच्च-से-इकाई परीक्षण) परीक्षण में Mockito.verify() का उपयोग करना चाहिए * मुझे लगता है कि इस सवाल का जवाब स्पष्ट रूप से है नहीं, इसके अलावा आप के लिए mocks उपयोग नहीं करना चाहिए? इस। आपका परीक्षण यथासंभव वास्तविक एप्लिकेशन के करीब होना चाहिए। आप पूर्ण उपयोग केस का परीक्षण कर रहे हैं, आवेदन के अलग हिस्से नहीं।

* ब्लैक बॉक्स बनाम व्हाइट बॉक्स इकाई परीक्षण * आप उपयोग कर रहे ब्लैक बॉक्स दृष्टिकोण क्या तुम सच में क्या कर रहा है, तो आप की आपूर्ति है (सभी तुल्यता वर्ग) इनपुट, एक राज्य, और परीक्षण जो आपको अपेक्षित आउटपुट प्राप्त करेंगे। इस दृष्टिकोण में सामान्य रूप से मोजे का उपयोग करना उचित है (आप सिर्फ नकल करते हैं कि वे सही काम कर रहे हैं; आप उनका परीक्षण नहीं करना चाहते हैं), लेकिन Mockito.verify() को कॉल करना अनिवार्य है।

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

ग्रे-बॉक्स-परीक्षण के लिए अंगूठे के नियम सफेद-बॉक्स परीक्षण के साथ समस्या यह एक उच्च युग्मन बनाता है। एक संभावित समाधान ग्रे-बॉक्स-परीक्षण करना है, सफेद-बॉक्स-परीक्षण नहीं। यह काले & सफेद बॉक्स परीक्षण के संयोजन का प्रकार है। आप वास्तव में व्यवहार का परीक्षण कर रहे हैं जैसे आपकी श्वेत-बॉक्स परीक्षण में, लेकिन आम तौर पर आप इसे पर कार्यान्वयन-अज्ञेय बनाते हैं। जब यह संभव हो, तो आप केवल ब्लैक-बॉक्स केस की तरह चेक बनायेंगे, केवल यह दावा करता है कि आउटपुट आपकी अपेक्षा की जाती है। तो, जब संभव हो तो आपके प्रश्न का सार तब होता है।

यह वास्तव में कठिन है। मेरे पास एक अच्छा उदाहरण नहीं है, लेकिन मैं आपको उदाहरणों के लिए दे सकता हूं। जिस मामले में उपरोक्त वर्णित किया गया है() बनाम बराबर इग्नोरकेस() आपको Mockito.verify() को कॉल नहीं करना चाहिए, बस आउटपुट पर जोर दें। यदि आप ऐसा नहीं कर पा रहे हैं, तो छोटे कोड को अपना कोड तोड़ दें, जब तक आप इसे नहीं कर सकते। दूसरी तरफ, मान लीजिए कि आपके पास कुछ @ सेवा है और आप @ वेब-सेवा लिख ​​रहे हैं जो अनिवार्य रूप से आपके @ सेवा पर रैपर है - यह सभी कॉल @Service (और कुछ अतिरिक्त त्रुटि प्रबंधन करने) को प्रतिनिधि करता है। इस मामले में Mockito.verify() को कॉल करना आवश्यक है, आपको अपने सभी चेक को डुप्लिकेट नहीं करना चाहिए जो आपने @Serive के लिए किया था, यह सत्यापित करते हुए कि आप सही पैरामीटर सूची के साथ @Service पर कॉल कर रहे हैं, पर्याप्त है।

+0

ग्रे बॉक्स परीक्षण एक गड़बड़ी का एक सा है। मैं इसे डीएओ जैसी चीजों तक सीमित कर देता हूं। ग्रे ग्रे बॉक्स परीक्षणों की एक बहुतायत के कारण, धीमे निर्माण के साथ कुछ परियोजनाओं पर मैं बहुत धीमी गति से निर्माण कर रहा हूं, यूनिट परीक्षणों की नज़दीकी पूर्ण कमी और ग्रेबॉक्स परीक्षणों का परीक्षण करने वाले ट्रस्ट की कमी की क्षतिपूर्ति के लिए बहुत सारे ब्लैकबॉक्स परीक्षणों के रास्ते। –

6

मुझे कहना पड़ेगा, कि आप को देखने के एक शास्त्रीय दृष्टिकोण के दृष्टिकोण से बिल्कुल सही कर रहे हैं:

  • हैं तो सबसे पहले बनाने (या परिवर्तन) व्यापार तर्क अपने आवेदन के और फिर के साथ कवर (अपनाने) परीक्षण (टेस्ट-अंतिम दृष्टिकोण), तो यह बहुत दर्दनाक और खतरनाक होगा कि परीक्षणों को इनपुट और आउटपुट की जांच के अलावा, आपके सॉफ़्टवेयर कैसे काम करता है, इस बारे में कुछ भी जानना खतरनाक और खतरनाक होगा।
  • यदि आप Test-Driven approach का अभ्यास कर रहे हैं, तो आपके परीक्षण आपके सॉफ़्टवेयर की कार्यक्षमता के first to be written, to be changed and to reflect the use cases हैं। कार्यान्वयन परीक्षणों पर निर्भर करता है। कभी-कभी इसका मतलब है कि आप चाहते हैं कि आपका सॉफ़्टवेयर किसी विशेष तरीके से कार्यान्वित किया जाए, उदा। किसी अन्य घटक की विधि पर भरोसा करें या इसे एक विशेष मात्रा में भी कॉल करें। वह जगह है जहां Mockito.verify() काम में आता है!

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

0

कुछ लोगों के रूप में कहा

  1. कभी कभी आप एक सीधा उत्पादन जिस पर आप जोर कर सकते हैं
  2. कभी कभी आप बस पुष्टि करें कि आपके परीक्षण किया विधि अपने सहयोगियों को सही अप्रत्यक्ष आउटपुट भेज रहा है की जरूरत नहीं है (जो आप मजाक कर रहे हैं)।

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

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