इंटरफेस (यूनिट परीक्षण, IoC?) का उपयोग कब करें?


17

मुझे संदेह है कि मैंने यहां एक स्कूलबॉय त्रुटि की है, और मैं स्पष्टीकरण की तलाश कर रहा हूं। मेरे समाधान में बहुत सी कक्षाएं (C #) - मैं बहुमत कहता हूं - मैंने इसके लिए एक संबंधित इंटरफ़ेस लिखना समाप्त कर दिया है। उदाहरण के लिए "ICalculator" इंटरफ़ेस और "कैलकुलेटर" वर्ग जो इसे लागू करता है, भले ही मुझे उस कैलकुलेटर को एक अलग कार्यान्वयन के साथ बदलने की संभावना नहीं है। इसके अलावा, इनमें से अधिकांश वर्ग अपनी निर्भरता के रूप में एक ही परियोजना में रहते हैं - उन्हें वास्तव में केवल होना चाहिए internal, लेकिन publicउनके संबंधित इंटरफेस को लागू करने के साइड-इफेक्ट के रूप में समाप्त हो गए हैं ।

मुझे लगता है कि कुछ झूठों से उपजी हर चीज के लिए इंटरफेस बनाने की यह प्रथा: -

1) मैंने मूल रूप से सोचा था कि यूनिट टेस्ट मॉक बनाने के लिए एक इंटरफ़ेस आवश्यक था (मैं Moq का उपयोग कर रहा हूं), लेकिन मैंने तब से पता लगाया है कि यदि कोई वर्ग इसके सदस्य हैं virtual, तो इसका मजाक उड़ाया जा सकता है , और इसका एक पैरामीटर रहित निर्माता है (मुझे सही करें मैं गलत हूँ)।

2) मुझे लगता है कि मूल रूप से आईओसी ढांचे (कैसल विंडसर) के साथ एक वर्ग को पंजीकृत करने के लिए एक इंटरफ़ेस आवश्यक था, उदाहरण के लिए

Container.Register(Component.For<ICalculator>().ImplementedBy<Calculator>()...

जब वास्तव में मैं सिर्फ अपने खिलाफ ठोस प्रकार दर्ज कर सकता था:

Container.Register(Component.For<Calculator>().ImplementedBy<Calculator>()...

3) इंटरफेस का उपयोग करना, जैसे निर्भरता इंजेक्शन के लिए निर्माण पैरामीटर, "ढीले युग्मन" में परिणाम।

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

संपादित करें : - मैं सिर्फ Moq के साथ एक नाटक कर रहा हूं, और यह सार्वजनिक और आभासी होने के लिए तरीकों की आवश्यकता लगती है , और एक सार्वजनिक पैरामीटर रहित निर्माता है, ताकि उनका मजाक उड़ाया जा सके। तो ऐसा लगता है कि मेरे पास आंतरिक कक्षाएं नहीं हो सकती हैं?


मुझे पूरा यकीन है कि एक इंटरफ़ेस को लागू करने के लिए आपको सी # को सार्वजनिक करने की आवश्यकता नहीं है, भले ही इंटरफ़ेस सार्वजनिक हो ...
vaughandroid

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

@ प्रश्न में परियोजना को एक UI परियोजना है, जहां सभी वर्गों को आंतरिक बनाना स्वाभाविक लगता था, लेकिन उन्हें अभी भी इकाई परीक्षण की आवश्यकता है? मैंने आंतरिक तरीकों का परीक्षण करने की आवश्यकता नहीं होने के बारे में कहीं और पढ़ा है, लेकिन मैंने उन कारणों को कभी नहीं समझा है।
एंड्रयू स्टीफंस

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

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

जवाबों:


7

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

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


1
उत्तर के लिए धन्यवाद। जैसा कि उल्लेख किया गया है, कुछ गलत कारण हैं कि मैंने क्या किया, भले ही मुझे पता था कि ज्यादातर इंटरफेस एक कार्यान्वयन से अधिक कभी नहीं होंगे। समस्या का एक हिस्सा मैं Moq फ्रेमवर्क का उपयोग कर रहा हूं जो इंटरफेस को मॉक करने के लिए बहुत अच्छा है, लेकिन क्लास को मॉक करने के लिए यह सार्वजनिक होना चाहिए, एक सार्वजनिक पैरामीटर रहित ctr है, और मॉक किए जाने वाले तरीके 'सार्वजनिक वर्चुअल' होने चाहिए)।
एंड्रयू स्टीफंस

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

1
@AndrewStephens - दुनिया की हर चीज़ का मज़ाक नहीं उड़ाया जाता। यदि कक्षाएं ठोस हैं (या कसकर युग्मित हैं) को इंटरफेस की आवश्यकता नहीं है, तो वे पर्याप्त रूप से उपयोग करने के लिए पर्याप्त हैं जैसा कि इकाई परीक्षण में है। समय / जटिलता moq-ing उन्हें परीक्षण लाभ के लायक नहीं है।
तेलस्तीन

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

1
@ विल्बर्ट - निश्चित रूप से, एक छोटा इंटरफ़ेस वर्ग की तुलना में अधिक पठनीय है, लेकिन आप एक या दूसरे को नहीं उठा रहे हैं, आपके पास कक्षा या एक वर्ग और एक इंटरफ़ेस है। और आप मेरे उत्तर में बहुत अधिक पढ़ रहे होंगे। मैं यह नहीं कह रहा हूं कि एक कार्यान्वयन के लिए कभी भी इंटरफेस बनाएं - वास्तव में सबसे अधिक, चूंकि अधिकांश इंटरैक्शन में उस लचीलेपन की आवश्यकता होनी चाहिए। लेकिन प्रश्न को फिर से पढ़ें। हर चीज के लिए एक इंटरफेस बनाना सिर्फ कार्गो की खेती है। IoC एक कारण नहीं है। मोक्स एक कारण नहीं हैं। आवश्यकताएं उस लचीलेपन को लागू करने का एक कारण हैं।
तेलस्टिन ऑग

4

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

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

3) यह कैसे झूठ है?

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


3

IoC का विचार ठोस प्रकार को बदली बनाना है। तो भले ही (अभी) आपके पास केवल एक ही कैलकुलेटर है जो ICalculator को लागू करता है, एक दूसरा कार्यान्वयन केवल इंटरफ़ेस पर निर्भर हो सकता है और कैलकुलेटर से कार्यान्वयन विवरण पर नहीं।

इसलिए, आपके IoC- कंटेनर पंजीकरण का पहला संस्करण सही है, और जिसे आपको भविष्य में उपयोग करना चाहिए।

यदि आप अपनी कक्षाओं को सार्वजनिक करते हैं या आंतरिक वास्तव में संबंधित नहीं है, और न ही moq-ing है।


2

मैं वास्तव में इस तथ्य से अधिक चिंतित हूं कि आप अपनी पूरी परियोजना में हर प्रकार के बारे में "नकली" होने की आवश्यकता महसूस करते हैं।

टेस्ट डबल्स ज्यादातर आपके कोड को बाहरी दुनिया (तृतीय-पक्ष के लिबास, डिस्क IO, नेटवर्क IO इत्यादि) या वास्तव में महंगी गणनाओं से अलग करने के लिए उपयोगी होते हैं। अपने अलगाव ढांचे के साथ बहुत उदार होने के नाते (क्या आपको भी वास्तव में इसकी आवश्यकता है? क्या आपकी परियोजना जटिल है?) आसानी से उन परीक्षणों का नेतृत्व कर सकती है जो कार्यान्वयन के लिए युग्मित हैं, और यह आपके डिजाइन को अधिक कठोर बनाता है। यदि आप परीक्षणों का एक गुच्छा लिखते हैं जो यह सत्यापित करते हैं कि कुछ वर्ग ने उस क्रम में X और Y को विधि कहा है, और फिर Z को विधि के लिए a, b और c से पास किया है, तो क्या आप वास्तव में मान प्राप्त कर रहे हैं? कभी-कभी आपको इस तरह के परीक्षण मिलते हैं जब तीसरे पक्ष के कामों के साथ लॉगिंग या इंटरैक्शन का परीक्षण होता है, लेकिन यह अपवाद होना चाहिए, नियम नहीं।

जैसे ही आपका आइसोलेशन फ्रेमवर्क आपको बताता है कि आपको सामान को सार्वजनिक करना चाहिए और आपके पास हमेशा पैरामीटर रहित कंस्ट्रक्टर होना चाहिए, यह चकमा देने के लिए चकमा देने का समय है, क्योंकि इस समय आपका फ्रेमवर्क आपको बुरा (बुरा) कोड लिखने के लिए मजबूर कर रहा है।

इंटरफेस के बारे में विशेष रूप से बोलते हुए, मुझे लगता है कि वे कुछ महत्वपूर्ण मामलों में उपयोगी हैं:

  • जब आपको विभिन्न प्रकारों में विधि कॉल भेजने की आवश्यकता होती है, जैसे जब आपके पास कई कार्यान्वयन होते हैं (यह स्पष्ट है, क्योंकि अधिकांश भाषाओं में इंटरफ़ेस की परिभाषा सिर्फ आभासी विधियों का एक संग्रह है)

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

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


1

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

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