2012-02-22 15 views
7

संभव डुप्लिकेट:
Using IoC for Unit Testingसंयोजन यूनिट टेस्ट (मजाक) और एक निर्भरता इंजेक्शन फ्रेमवर्क

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

(मैं इसे साफ और आसान रखने के लिए एक अच्छा उदाहरण बनाने की कोशिश करूंगा। यह मेरे बारे में है, बाइक की सवारी)।

1.) डि बिना/यूनिट टेस्ट:
डि और यूनिट टेस्ट के बिना जाने, मेरे कोड इस तरह देखा होगा - और मैं खुशी होगी:

public class Person 
{ 
    public void Travel() 
    { 
     Bike bike = new Bike(); 
     bike.Ride(); 
    } 
} 

public class Bike 
{ 
    public void Ride() 
    { 
     Console.WriteLine("Riding a Bike"); 
    } 
} 

सवारी करने के लिए मेरी बाइक मैं होता बस जरूरत है: new Person().Travel();

2.) डि के साथ:
मुझे लगता है कि तंग युग्मन नहीं करना चाहते, तो मैं एक अंतरफलक और एक NinjectModule की जरूरत है! मेरे पास कुछ ओवरहेड होगा, लेकिन यह ठीक होगा, जब तक कोड को पढ़ने और समझने में आसान हो। मैं सिर्फ संशोधित व्यक्ति वर्ग के लिए कोड पारित होगा, बाइक वर्ग अपरिवर्तित है:

public class Person 
{ 
    IKernel kernel = new StandardKernel(new TransportationModule()); 
    public void Travel() 
    { 
     ITransportation transportation = kernel.Get<ITransportation>(); 
     transportation.Ride(); 
    } 
} 

मैं अभी भी बस के साथ अपने मोटर साइकिल की सवारी कर सकते हैं: new Person().Travel();

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

public class Person 
{ 
    ITransportation transportation; 

    public person(ITransportation transportation) 
    { 
     this.transportation = transportation; 
    } 

    public void Travel() 
    { 
     transportation.Ride(); 
    } 
} 

इस बार, मैं बाइक से पारित करने के लिए neet होगा: new Person(new Bike()).Travel();

4.) डि के साथ और यूनिट टेस्ट
में वर्ग के लिए तैयारी 3. यूनिट-टेस्टिंग (डीआई के बिना) ध्यान में बिना काम किए काम करेगा, लेकिन मुझे new Person(kernel.Get<ITransportation>()); पर कॉल करने की आवश्यकता होगी। इसके माध्यम से, ऐसा लगता है कि मैं डीआई से लाभ खो रहा हूं - व्यक्ति वर्ग किसी भी युग्मन के बिना यात्रा को कॉल कर सकता है और यह जानने की आवश्यकता है कि परिवहन किस प्रकार की कक्षा है। साथ ही, मुझे लगता है कि इस फॉर्म में उदाहरण की बहुत अधिक पठनीयता की कमी है।

क्या यह किया जाता है? या क्या अन्य - निर्भरता इंजेक्शन और इकाई परीक्षण (और नकली) की संभावना को प्राप्त करने के अधिक सुंदर तरीके हैं?

(वापस देखकर, ऐसा लगता है कि उदाहरण वास्तव में बुरा है - हर किसी को पता होना चाहिए कि इस समय वह किस तरह का परिवहन उपकरण सवारी कर रहा है ...)

+0

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

+0

zapthedingbat सही है। आप तीसरे उदाहरण में डी कर रहे हैं, लेकिन डीआई कंटेनर का उपयोग न करें, जो ठीक है। डीआई करते समय डी कंटेनर वैकल्पिक है। – Steven

+1

उदाहरण "2." DI का उपयोग नहीं करता है, लेकिन एक "सेवा लोकेटर" ... –

उत्तर

10

आम तौर पर मैं अपने यूनिट परीक्षण के लिए आईओसी कंटेनर का उपयोग करने से बचने की कोशिश करता हूं - निर्भरताओं में पास करने के लिए बस मोजे और स्टब्स का उपयोग करें।

आपकी समस्या परिदृश्य 2 में शुरू होती है: यह नहीं DI - यह service locator (anti-)pattern है। असली निर्भरता के लिए इंजेक्शन आपको कन्स्ट्रक्टर इंजेक्शन के माध्यम से, अपनी निर्भरताओं में गुजरना होगा।

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

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

इकाई परीक्षण में एक आईओसी कंटेनर का उपयोग कर के खिलाफ एक अंतिम और महत्वपूर्ण तर्क है व्यवहार परीक्षण: कैसे क्या आप वाकई परीक्षण के अंतर्गत कक्षा जिस तरह से आप अगर आप अपने निर्भरता का पूरा नियंत्रण में नहीं हैं करने के लिए यह चाहते बर्ताव करता है हो सकता है?

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

4

आपको कुछ चीजें उलझन में मिल रही हैं।

कार्यान्वयन 3 संख्या 2 के बाद बेहतर है, क्योंकि आपको अपने यूनिट परीक्षणों में डी फ्रेमवर्क सेट करने की आवश्यकता नहीं है।

तो जब नंबर 3 का परीक्षण कर आप क्या करेंगे:

ITransportation transportationMock = MockRepository.GenerateStricktMock<ITransportation>(); 

// setup exceptations on your mock 

var person = new Person(transportationMock); 

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

यदि आप कुछ एकीकरण परीक्षण भी करना चाहते हैं तो आप अपनी व्यक्तिगत कक्षा में वास्तविक बाइक पास करेंगे और इसका परीक्षण करेंगे।

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

टेस्टेबल कोड लिखने की कुंजी व्यापार तर्क से वस्तु निर्माण को विभाजित करना है।

3

मेरे 2 सेंट ...

हालांकि बिंदु 2 निर्भरता उलट सिद्धांत (DIP) का एक उदाहरण है, यह नहीं बल्कि निर्भरता इंजेक्शन की तुलना में सेवा स्थान पैटर्न का उपयोग करता है,।

आपका पॉइंट 3 इलस्ट्रेट्स निर्भरता इंजेक्शन, जहां आईओसी कंटेनर व्यक्ति के निर्माण के दौरान कन्स्ट्रक्टर में निर्भरता (आईट्रांसपोर्टेशन) इंजेक्ट करेगा।

अपने असली ऐप और यूनिट परीक्षण में, आप आईओसी कंटेनर का उपयोग व्यक्ति को भी बनाने के लिए करना चाहते हैं (यानी सीधे नया व्यक्ति न करें)। यदि आपका यूनिट टेस्ट फ्रेमवर्क इसका समर्थन करता है तो या तो सेवा लोकेटर पैटर्न (kernel.Get<Person>();), या DI (उदा। सेटर) का उपयोग करें।

यह तो व्यक्ति और उसके निर्भरता (ITransportation के लिए कॉन्फ़िगर ठोस वर्ग अर्थात्) बनाएँ और सम्मिलित करें कि व्यक्ति में भी होगा (अपने आईओसी का परीक्षण जाहिर है, इकाई में मज़ाक उड़ाया के लिए कॉन्फ़िगर कर दिया जाएगा/टोंटदार ITransportation)

अंत में, यह निर्भरता है कि आप मॉक करना चाहते हैं, यानी आईट्रांसपोर्टेशन, ताकि आप व्यक्ति के परिवहन() विधि का परीक्षण कर सकें।

चूंकि बाइक की कोई निर्भरता नहीं है, इसलिए यूनिट को सीधे/स्वतंत्र रूप से परीक्षण किया जा सकता है (बाइक में एक निर्भरता को जोड़ा जाने तक आपको बाइक.राइड() का परीक्षण करने के लिए नकली की आवश्यकता नहीं है)।

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