C # और राइनोमॉक्स के प्रयोग से टेस्ट ड्रिवेन डेवलपमेंट के सर्वश्रेष्ठ अभ्यास [बंद]


86

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

कोड की परीक्षण क्षमता को अधिकतम करने के लिए, इन नियमों का पालन करें:

  1. पहले टेस्ट लिखें, फिर कोड। कारण: यह सुनिश्चित करता है कि आप परीक्षण योग्य कोड लिखें और कोड की प्रत्येक पंक्ति को इसके लिए लिखे गए परीक्षण मिलें।

  2. निर्भरता इंजेक्शन का उपयोग कर डिजाइन कक्षाएं। कारण: आप मॉक या टेस्ट नहीं कर सकते कि क्या नहीं देखा जा सकता।

  3. मॉडल-व्यू-कंट्रोलर या मॉडल-व्यू-प्रस्तोता का उपयोग करके अपने व्यवहार से अलग यूआई कोड। कारण: व्यापार तर्क का परीक्षण करने की अनुमति देता है जबकि उन भागों का परीक्षण नहीं किया जा सकता है (UI) कम से कम।

  4. स्थिर तरीके या कक्षाएं न लिखें। कारण: स्टेटिक तरीके अलग करना मुश्किल या असंभव है और राइनो मॉक उनका मजाक नहीं उड़ा पा रहे हैं।

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

  6. बाहरी निर्भरता को अलग करें। कारण: अनारक्षित बाहरी निर्भरता का परीक्षण नहीं किया जा सकता है।

  7. वर्चुअल के रूप में चिह्नित करें जो आप नकली करने का इरादा रखते हैं। कारण: राइनो मॉक्स गैर-आभासी तरीकों का मजाक उड़ाने में असमर्थ हैं।


यह एक उपयोगी सूची है। वर्तमान में हम NUnit और Rhino.Mocks का उपयोग कर रहे हैं, और टीम के सदस्यों के लिए इन मानदंडों को बाहर करना अच्छा है जो यूनिट परीक्षण के इस पक्ष से कम परिचित हैं।
क्रिस बल्डर्ड

जवाबों:


58

निश्चित रूप से एक अच्छी सूची। इस पर कुछ विचार हैं:

पहले टेस्ट लिखें, फिर कोड।

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

निर्भरता इंजेक्शन का उपयोग कर डिजाइन कक्षाएं।

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

मॉडल-व्यू-कंट्रोलर या मॉडल-व्यू-प्रस्तोता का उपयोग करके अपने व्यवहार से अलग यूआई कोड।

माना। ध्यान दें कि यहां तक ​​कि प्रस्तुतकर्ता / नियंत्रक को DI / IoC का उपयोग करके परीक्षण किया जा सकता है, इसे एक ठूंठ / नकली दृश्य और मॉडल को सौंपकर। चेक आउट प्रस्तुतकर्ता पहले कि अधिक जानकारी के लिए TDD।

स्थिर तरीके या कक्षाएं न लिखें।

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

कार्यक्रम बंद नहीं, इंटरफेस।

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

बाहरी निर्भरता को अलग करें।

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

वर्चुअल के रूप में चिह्नित करें जो आप नकली करने का इरादा रखते हैं।

वह राइनो मोक्स की एक सीमा है। ऐसे वातावरण में, जो मॉक ऑब्जेक्ट फ्रेमवर्क पर हाथ से कोड किए गए स्टब्स को पसंद करता है, जो आवश्यक नहीं होगा।

और, नए बिंदुओं पर विचार करने के लिए:

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

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

अपने खुद के मॉक / स्टब्स को रोल करने से डरो मत। अक्सर, आप पाएंगे कि नकली ऑब्जेक्ट फ्रेमवर्क का उपयोग करना आपके परीक्षणों को पढ़ने के लिए अविश्वसनीय रूप से कठिन बनाता है। अपना स्वयं का रोल करके, आप अपने मोक्स / स्टब्स पर पूरा नियंत्रण रखेंगे, और आप अपने परीक्षणों को पठनीय रख पाएंगे। (पिछले बिंदु पर वापस जाएँ।)

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

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


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

10

यदि आप .Net 3.5 के साथ काम कर रहे हैं, तो आप Moq मॉकिंग लाइब्रेरी में देखना चाह सकते हैं - यह अभिव्यक्ति के पेड़ों और लैम्ब्डा का उपयोग करता है, जो कि अधिकांश अन्य मॉकिंग लाइब्रेरी के गैर-सहज ज्ञान युक्त रिकॉर्ड-उत्तर मुहावरे को दूर करता है।

इस क्विकस्टार्ट को देखें कि आपके परीक्षण के मामले कितने सहज हैं, यह एक सरल उदाहरण है:

// ShouldExpectMethodCallWithVariable
int value = 5;
var mock = new Mock<IFoo>();

mock.Expect(x => x.Duplicate(value)).Returns(() => value * 2);

Assert.AreEqual(value * 2, mock.Object.Duplicate(value));

5
मुझे लगता है कि राइनो मोक्स का नया संस्करण इस तरह से भी काम करता है
जॉर्ज माउर

6

फेक, मॉक और स्टब्स के बीच अंतर और प्रत्येक का उपयोग कब करना है , इसके बारे में जानें ।

मोज़ेक का उपयोग करके बातचीत को निर्दिष्ट करने से बचें। यह परीक्षणों को भंगुर बनाता है ।


3

यह एक बहुत ही उपयोगी पोस्ट है!

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

आप में से कुछ के लिए, जो पूरी तरह से अकादमिक दुनिया में रहते हैं, समयसीमा और डिलीवरी महत्वपूर्ण नहीं हो सकती है, लेकिन ऐसे माहौल में जहां सॉफ्टवेयर पैसा है, आपके टीडीडी प्रयास का प्रभावी उपयोग महत्वपूर्ण है।

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

मुझे विश्वास है कि टीडीडी का प्राथमिक मूल्य सीमा (ब्लैकबॉक्स) के साथ-साथ सिस्टम के मिशन-महत्वपूर्ण क्षेत्रों के सामयिक व्हाइटबॉक्स परीक्षण में है।


2

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


सहमत ... मैं यह दर्शाने के लिए अपने प्रश्न को अपडेट करने जा रहा हूं।
केविन अल्ब्रेक्ट

1

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

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


मैं एक व्यक्तिगत परियोजना में एक समान BDD शैली परीक्षण अनुभाग (इकाई परीक्षण कोड के अलावा) भी करता हूं।
केविन अल्ब्रेक्ट

0

यहाँ एक और बात है कि मुझे लगा कि मुझे ऐसा करना पसंद है।

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

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

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