यूनिट एक ऐसे वर्ग का परीक्षण करता है, जो आंतरिक पर परीक्षण के बिना DI का उपयोग करता है


12

मेरे पास एक वर्ग है जिसे 1 मुख्य वर्ग और 2 छोटे वर्गों में दर्शाया गया है। मुख्य कक्षाएं डेटाबेस का उपयोग करती हैं (जैसे मेरी बहुत सारी कक्षाएं करती हैं) और एक ईमेल भेजती हैं। तो मुख्य वर्ग में एक IPersonRepositoryऔर एक IEmailRepositoryइंजेक्शन है जो उसकी बारी में 2 छोटे वर्गों को भेजता है।

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

लेकिन जैसे-जैसे वर्ग का उपयोग करता है IPersonRepositoryऔर एक IEmailRepository, मैं है (नकली / डमी) के लिए कुछ तरीकों के लिए परिणाम निर्दिष्ट करने के लिए IPersonRepository। मुख्य वर्ग मौजूदा डेटा और रिटर्न के आधार पर कुछ डेटा की गणना करता है। अगर मैं उसका परीक्षण करना चाहता हूं, तो मैं यह नहीं देखता कि मैं IPersonRepository.GetSavingsByCustomerIdरिटर्न एक्स को निर्दिष्ट किए बिना कैसे एक परीक्षण लिख सकता हूं । लेकिन तब मेरी इकाई परीक्षा आंतरिक कामकाज के बारे में 'जानती है', क्योंकि यह 'जानता है' कि किस तरीके का मजाक उड़ाया जाए और कौन सा नहीं।

मैं एक ऐसे वर्ग का परीक्षण कैसे कर सकता हूं, जिसने आंतरिक के बारे में जानने के बिना परीक्षण पर निर्भरता का इंजेक्शन लगाया है?

पृष्ठभूमि:

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

अब मैंने सिद्धांत के बारे में एक प्रस्तुति देखी है (जो मैंने पहले सुना है) कि परीक्षण को कार्यान्वयन के बारे में पता नहीं होना चाहिए। पहले क्योंकि आप परीक्षण नहीं कर रहे हैं कि यह कैसे काम करता है, बल्कि इसलिए भी कि जब आप कार्यान्वयन को बदलते हैं तो सभी इकाई परीक्षण विफल हो जाते हैं क्योंकि वे कार्यान्वयन के बारे में 'जानते हैं'। हालांकि मुझे परीक्षणों की अवधारणा कार्यान्वयन से अनजान होने के कारण पसंद है, मुझे नहीं पता कि इसे कैसे पूरा किया जाए।


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

जवाबों:


7

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

आप सही हैं कि यह "आंतरिक परीक्षण न करें" सिद्धांत का उल्लंघन है और एक आम बात है जिसे लोग नजरअंदाज करते हैं।

मैं एक ऐसे वर्ग का परीक्षण कैसे कर सकता हूं, जिसने आंतरिक के बारे में जानने के बिना परीक्षण पर निर्भरता का इंजेक्शन लगाया है?

इस उल्लंघन के चारों ओर काम करने के दो उपाय हैं जिन्हें आप अपना सकते हैं:

1) का पूरा नकली प्रदान करें IPersonRepository। आपके वर्तमान में वर्णित दृष्टिकोण है कि परीक्षण के तहत विधि के आंतरिक कामकाज के लिए मॉक को केवल उन तरीकों को मॉक करके जो वे कहेंगे। यदि आप सभी तरीकों के लिए नकली आपूर्ति करते हैं IPersonRepository, तो आप उस युग्मन को हटा देते हैं। आंतरिक कामकाज मॉक को प्रभावित किए बिना बदल सकता है, इस प्रकार परीक्षण कम भंगुर बनाता है।

इस दृष्टिकोण को DI तंत्र को सरल रखने का लाभ है, लेकिन यह बहुत काम पैदा कर सकता है यदि आपका इंटरफ़ेस कई तरीकों को परिभाषित करता है।

2) इंजेक्शन न करें IPersonRepository, या तो GetSavingsByCustomerIdविधि को इंजेक्ट करें , या बचत मूल्य को इंजेक्ट करें। संपूर्ण इंटरफ़ेस कार्यान्वयनों को इंजेक्ट करने में समस्या यह है कि आप तब दो दृष्टिकोणों को मिलाते हुए एक "पूछें, न बताएं" सिस्टम को "पूछें, न बताएं" को इंजेक्ट कर रहे हैं। यदि आप "शुद्ध DI" दृष्टिकोण लेते हैं, तो विधि को एक सटीक मूल्य प्रदान करने के बजाय कॉल करने की सटीक विधि (बताई गई) चाहिए, जो वस्तु दी जा रही है (जो कि तब उसे प्रभावी रूप से कॉल करने की विधि के लिए पूछना चाहिए)।

इस दृष्टिकोण का लाभ यह है कि यह मोक्स (परीक्षण विधियों से परे है कि आप परीक्षण के तहत विधि में इंजेक्ट करते हैं) की आवश्यकता से बचा जाता है। नुकसान यह है कि यह विधि हस्ताक्षरों को बदलने की विधि की आवश्यकताओं के जवाब में बदल सकता है।

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


1
मुझे वास्तव में विचार संख्या 2 पसंद है। मुझे नहीं पता कि मैंने पहले क्यों नहीं सोचा है। मैं काफी सालों से IRepositories पर निर्भरता पैदा कर रहा हूं, अब बिना किसी सवाल के खुद पर सवाल उठा रहा हूं कि मैंने पूरे IRepository पर निर्भरता क्यों बनाई (जिसमें बहुत सारे मामलों में काफी विधि हस्ताक्षर होंगे) जबकि यह केवल एक पर निर्भरता है 2 विधियाँ। इसलिए एक IRepository को इंजेक्ट करने के बजाय मैं (केवल) विधि हस्ताक्षर की आवश्यकता के साथ बेहतर इंजेक्शन लगा सकता हूं या पास कर सकता हूं।
मिशेल '

1

मेरा दृष्टिकोण रिपॉजिटरी के 'नकली' संस्करणों को बनाना है जो सरल फाइलों से पढ़ते हैं जिनमें आवश्यक डेटा होता है।

इसका मतलब यह है कि व्यक्तिगत परीक्षण मॉक के सेटअप के बारे में 'पता' नहीं करता है, हालांकि जाहिर है कि समग्र परीक्षण परियोजना मॉक को संदर्भित करेगी और सेटअप फाइलें आदि होंगी।

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

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


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

1
यह समझाने के लिए संपादित किया गया कि मेरा दृष्टिकोण बेहतर क्यों है, हालांकि अभी भी उस परिदृश्य के लिए बिल्कुल सही नहीं है जो मुझे लगता है कि आपका मतलब है
इवान

1

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

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

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