यूनिट परीक्षण शून्य विधियाँ?


170

यूनिट के परीक्षण का सबसे अच्छा तरीका क्या है जो कुछ भी वापस नहीं करता है? विशेष रूप से c # में।

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


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

जवाबों:


151

यदि कोई विधि कुछ भी वापस नहीं करती है, तो यह निम्नलिखित में से एक है

  • अनिवार्य - आप या तो वस्तु को खुद से कुछ करने के लिए कह रहे हैं .. उदाहरण के लिए स्थिति बदलें (किसी भी पुष्टि की उम्मीद किए बिना .. इसका अनुमान है कि यह हो जाएगा)
  • सूचनात्मक - किसी को सूचित करना कि कुछ हुआ (क्रमशः कार्रवाई या प्रतिक्रिया की उम्मीद किए बिना)।

इम्पीरेटिव तरीके - यदि कार्य वास्तव में किया गया था, तो आप सत्यापित कर सकते हैं। सत्यापित करें कि क्या वास्तव में राज्य परिवर्तन हुआ था। जैसे

void DeductFromBalance( dAmount ) 

यदि यह संदेश वास्तव में dAmount द्वारा प्रारंभिक मान से कम है, तो पुष्टि करके परीक्षण किया जा सकता है

सूचनात्मक विधियाँ - वस्तु के सार्वजनिक इंटरफ़ेस के सदस्य के रूप में दुर्लभ हैं ... इसलिए आमतौर पर इकाई-परीक्षण नहीं किया जाता है। हालाँकि, यदि आपको आवश्यक है, तो आप यह सत्यापित कर सकते हैं कि क्या अधिसूचना पर किया जाना है। जैसे

void OnAccountDebit( dAmount )  // emails account holder with info

यदि ईमेल भेजा जा रहा है तो सत्यापित करके परीक्षण किया जा सकता है

अपनी वास्तविक विधि के बारे में अधिक जानकारी पोस्ट करें और लोग बेहतर उत्तर दे पाएंगे।
अपडेट : आपका तरीका 2 चीजें कर रहा है। मैं वास्तव में इसे दो तरीकों से विभाजित करूँगा जो अब स्वतंत्र रूप से जांचे जा सकते हैं।

string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );

स्ट्रिंग [] आसानी से एक डमी फ़ाइल और अपेक्षित स्ट्रिंग्स के साथ पहला तरीका प्रदान करके सत्यापित किया जा सकता है। दूसरा थोड़ा मुश्किल है .. आप DB को नकल करने या वास्तविक DB को हिट करने और यदि सही स्थान पर तार डाले गए थे, तो सत्यापित करने के लिए एक नकली (google या सर्च स्टैकओवरफ़्लो का उपयोग कर सकते हैं)। कुछ अच्छी किताबों के लिए इस धागे की जाँच करें ... यदि आप एक क्रंच में हैं तो मैं प्रोगैमैटिक यूनिट टेस्टिंग को फिर से करूँगा।
कोड में इसका उपयोग किया जाएगा

InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );

1
हे गिशु, अच्छा जवाब। आपने जो उदाहरण दिया ... वे अधिक एकीकरण टेस्ट नहीं हैं ...? और यदि ऐसा है, तो सवाल यह है कि कोई वास्तव में शून्य विधियों का परीक्षण कैसे करता है .... शायद यह असंभव है?
एंडी

2
@ कैंडी - 'एकीकरण परीक्षण' की आपकी परिभाषा पर निर्भर करता है। इम्पीरियल विधियां आमतौर पर राज्य को बदलती हैं, इसलिए आपको एक इकाई परीक्षण द्वारा सत्यापित किया जा सकता है जो ऑब्जेक्ट की स्थिति को पूछताछ करता है। सूचना के तरीकों को एक इकाई परीक्षण द्वारा सत्यापित किया जा सकता है जो एक नकली श्रोता / सहयोगी को प्लग करता है ताकि यह सुनिश्चित हो सके कि परीक्षण विषय सही अधिसूचना जारी करता है। मुझे लगता है कि दोनों को यूनिट परीक्षणों के माध्यम से उचित परीक्षण किया जा सकता है।
गिशु

@ कैंडी डेटाबेस को मॉक किया जा सकता है / इसे एक एक्सेसर इंटरफेस द्वारा अलग किया जा सकता है और इस प्रकार मॉक ऑब्जेक्ट को पास किए गए डेटा द्वारा कार्रवाई की जा सकती है।
पीटर गीगर

62

इसके दुष्प्रभावों का परीक्षण करें। यह भी शामिल है:

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

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


31

हमेशा की तरह: परीक्षण करें कि विधि क्या करने वाली है!

क्या यह वैश्विक स्थिति (उह, कोड गंध!) को कहीं बदलना चाहिए?

क्या इसे एक इंटरफ़ेस में कॉल किया जाना चाहिए?

क्या गलत मापदंडों के साथ बुलाए जाने पर इसे एक अपवाद फेंक देना चाहिए?

क्या इसे सही मापदंडों के साथ बुलाया जाने पर कोई अपवाद नहीं फेंकना चाहिए?

इसे होना चाहिए ...?


11

शून्य वापसी प्रकार / सबरूटीन पुरानी खबरें हैं। मैंने 8 साल की तरह (इस उत्तर के समय से, जब तक कि यह प्रश्न नहीं पूछा गया था) से पहले मैंने एक शून्य रिटर्न प्रकार (जब तक मैं बेहद आलसी हो रहा था) नहीं बना लिया।

इसके बजाय एक विधि की तरह:

public void SendEmailToCustomer()

Microsoft की int.TryParse () प्रतिमान का अनुसरण करने वाली विधि बनाएँ:

public bool TrySendEmailToCustomer()

हो सकता है कि आपके द्वारा लंबे समय से उपयोग में लाए जाने के लिए आपके द्वारा दी गई किसी भी जानकारी की आवश्यकता न हो, लेकिन अपना कार्य करने के बाद विधि की स्थिति को वापस करना कॉलर के लिए बहुत बड़ा उपयोग है।

इसके अलावा, बूल एकमात्र राज्य प्रकार नहीं है। कई बार ऐसा होता है जब पहले से निर्मित सबरूटीन वास्तव में तीन या अधिक विभिन्न राज्यों (गुड, नॉर्मल, बैड, आदि) को वापस कर सकता है। उन मामलों में, आप बस उपयोग करेंगे

public StateEnum TrySendEmailToCustomer()

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

यदि आप विधि-में-प्रश्न में डेटा एक्सेस सामान कर रहे हैं, तो आपको n-tier'd या n-layer'd आर्किटेक्चर में रिफ्लेक्टर करने की आवश्यकता है। लेकिन हम यह मान सकते हैं कि जब आप कहते हैं "तार फिर एक डेटाबेस में डाले जाते हैं", तो आप वास्तव में मतलब है कि आप एक व्यापार तर्क परत या कुछ और कह रहे हैं। हां, हम मान लेंगे।

जब आपकी वस्तु को त्वरित किया जाता है, तो अब आप समझते हैं कि आपकी वस्तु पर निर्भरता है। यह तब होता है जब आपको यह तय करने की आवश्यकता होती है कि क्या आप ऑब्जेक्ट पर, या विधि पर निर्भरता इंजेक्शन करने जा रहे हैं। इसका मतलब है कि आपके कंस्ट्रक्टर या विधि-में-प्रश्न को एक नए पैरामीटर की आवश्यकता है:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

अब जब आप अपने व्यवसाय / डेटा टियर ऑब्जेक्ट के एक इंटरफ़ेस को स्वीकार कर सकते हैं, तो आप इसे यूनिट टेस्ट के दौरान मॉक आउट कर सकते हैं और "निर्भरता" एकीकरण परीक्षण का कोई निर्भरता या भय नहीं है।

तो आपके लाइव कोड में, आप एक वास्तविक IBusinessDataEtcऑब्जेक्ट में पास होते हैं । लेकिन आपके यूनिट टेस्टिंग में, आप MOCK IBusinessDataEtcऑब्जेक्ट में पास होते हैं । उस Mock में आप नॉन-इंटरफ़ेस प्रॉपर्टीज़ जैसे int XMethodWasCalledCountया कुछ और शामिल कर सकते हैं जिसका स्टेट (s) इंटरफ़ेस मेथड्स कहे जाने पर अपडेट किया जाता है।

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

  1. "सबरूटीन" की स्थिति जो अब एक कोशिश-प्रतिमान विधि है।
  2. आपकी नकली IBusinessDataEtcवस्तु की स्थिति।

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


इस महान उत्तर का पहला हिस्सा सभी नौसिखिए / मध्यवर्ती प्रोग्रामर के लिए अद्भुत सामान्य सलाह के रूप में कार्य करता है।
अक्टूबर

क्या यह कुछ ऐसा नहीं होना चाहिए public void sendEmailToCustomer() throws UndeliveredMailException?
ए। ईमद

1
@ ए ईमद अच्छा सवाल है, लेकिन नहीं। अपवादों को फेंकने पर भरोसा करके अपने कोड के प्रवाह को नियंत्रित करना एक लंबे समय से ज्ञात बुरा अभ्यास है। हालाँकि, voidतरीकों में, विशेष रूप से ऑब्जेक्ट-ओरिएंटेड भाषाओं में, यह एकमात्र वास्तविक विकल्प रहा है। Microsoft द्वारा सबसे पुराना विकल्प Try-Paradigm I चर्चा करता है, और कार्यात्मक शैली प्रतिमान जैसे मोनाड्स / Maybes। इस प्रकार, कमांड (CQS में) अभी भी फेंकने पर भरोसा करने के बजाय मूल्यवान स्थिति की जानकारी वापस कर सकते हैं, जो कि एक GOTO(जो हम जानते हैं कि खराब है) के समान है। फेंक (और गोटो) धीमी, कठिन बहस करने के लिए, और अच्छा अभ्यास नहीं है।
सुमेरे

इसे साफ़ करने के लिए धन्यवाद। क्या यह C # विशिष्ट है या जावा और C ++ जैसी भाषाओं में भी अपवादों को फेंकना सामान्य रूप से बुरा व्यवहार है?
ए। ईमद

9

इसे इस्तेमाल करे:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}

1
यह आवश्यक नहीं होना चाहिए लेकिन ऐसा किया जा सकता है
नाथन एलार्ड

StackOverflow में आपका स्वागत है! कृपया अपने कोड में कुछ स्पष्टीकरण जोड़ने पर विचार करें। धन्यवाद।
औरसफ़ेरे

2
ExpectedAttributeअधिक स्पष्ट रूप से इस परीक्षण बनाने के लिए बनाया गया है।
मार्टिन लीवरेज

8

आप इसे इस तरह भी आजमा सकते हैं:

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}

1
यह सबसे आसान तरीका है जो मुझे लगता है।
नवीन पंडित

5

किसी वस्तु पर इसका कुछ प्रभाव होगा .... प्रभाव के परिणाम के लिए क्वेरी। यदि इसका कोई दृश्य प्रभाव नहीं है तो इसके इकाई परीक्षण के लायक नहीं है!


4

संभवतः विधि कुछ करती है, और बस वापस नहीं आती है?

यह मानते हुए कि मामला है, तब:

  1. यदि यह इसके स्वामी की स्थिति को संशोधित करता है, तो आपको परीक्षण करना चाहिए कि राज्य सही तरीके से बदल गया है।
  2. यदि यह किसी वस्तु को एक पैरामीटर के रूप में लेता है और उस वस्तु को संशोधित करता है, तो आपको परीक्षण करना चाहिए कि वस्तु सही ढंग से संशोधित है।
  3. यदि यह अपवादों को फेंकता है, तो निश्चित मामले हैं, परीक्षण करें कि उन अपवादों को सही ढंग से फेंक दिया गया है।
  4. यदि इसका व्यवहार अपनी वस्तु की स्थिति, या किसी अन्य वस्तु के आधार पर भिन्न होता है, तो राज्य को निर्धारित करें और विधि का परीक्षण करें, उपरोक्त तीन परीक्षण विधियों में से एक सही Ianth है)।

यदि आप हमें बताएं कि विधि क्या करती है, तो मैं अधिक विशिष्ट हो सकता है।


3

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


1
यूनिट टेस्ट कैसे करें इसका जवाब कभी भी थर्ड पार्टी टूल को नहीं मिलना चाहिए जो आपके लिए ऐसा करता है। हालांकि, जब कोई व्यक्ति जानता है कि इकाई परीक्षण कैसे किया जाता है, तो इसे आसान बनाने के लिए तीसरे पक्ष के उपकरण का उपयोग करना स्वीकार्य है।
Suamere

2

यह क्या कर रहा है पर निर्भर करता है। यदि इसके पैरामीटर हैं, तो ऐसे मोक्स में पास करें जो आप बाद में पूछ सकते हैं कि क्या उन्हें मापदंडों के सही सेट के साथ बुलाया गया है।


सहमत - विधि का परीक्षण करने वाले मोक्स के व्यवहार की पुष्टि करना एक तरीका होगा।
जेफ शूमाकर

0

शून्य विधि को कॉल करने के लिए आप किस उदाहरण का उपयोग कर रहे हैं, आप बस उपयोग कर सकते हैं,Verfiy

उदाहरण के लिए:

मेरे मामले में इसका _Logउदाहरण है और LogMessageपरीक्षण की जाने वाली विधि है:

try
{
    this._log.Verify(x => x.LogMessage(Logger.WillisLogLevel.Info, Logger.WillisLogger.Usage, "Created the Student with name as"), "Failure");
}
Catch 
{
    Assert.IsFalse(ex is Moq.MockException);
}

क्या Verifyपरीक्षण विफल होने की विधि की विफलता के कारण एक अपवाद है?

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