मुझे शुद्ध विधि के लिए एक परीक्षण कैसे लिखना चाहिए जो कुछ भी वापस नहीं करता है?


13

मेरे पास वर्गों का एक समूह है जो मूल्यों के सत्यापन से संबंधित है। उदाहरण के लिए, एक RangeValidatorवर्ग यह जांचता है कि कोई मान निर्दिष्ट सीमा के भीतर है या नहीं।

प्रत्येक सत्यापनकर्ता वर्ग में दो विधियाँ शामिल हैं: is_valid(value)जो कि रिटर्न Trueया Falseमूल्य पर निर्भर करता है, और ensure_valid(value)जो एक निर्दिष्ट मूल्य के लिए जाँच करता है और या तो कुछ भी नहीं करता है यदि मूल्य मान्य है, या एक विशिष्ट अपवाद को फेंकता है यदि मूल्य पूर्वनिर्धारित नियमों से मेल नहीं खाता है।

वर्तमान में इस पद्धति से जुड़े दो इकाई परीक्षण हैं:

  • वह जो अमान्य मान से गुजरता है, और यह सुनिश्चित करता है कि अपवाद को फेंक दिया गया था।

    def test_outside_range(self):
        with self.assertRaises(demo.ValidationException):
            demo.RangeValidator(0, 100).ensure_valid(-5)
    
  • वह जो एक वैध मान पास करता है।

    def test_in_range(self):
        demo.RangeValidator(0, 100).ensure_valid(25)
    

हालांकि दूसरा परीक्षण अपना काम करता है - यदि अपवाद फेंका जाता है, तो विफल रहता है और अगर ensure_validकुछ भी नहीं फेंकता है तो सफल होता है - इस तथ्य की कि assertअंदर कोई भी अजीब नहीं है। कोई व्यक्ति जो इस तरह के कोड को पढ़ता है, वह तुरंत खुद से पूछेगा कि ऐसा परीक्षण क्यों है जो कुछ भी नहीं करता प्रतीत होता है।

क्या यह एक मौजूदा अभ्यास है जब परीक्षण के तरीके जो एक मूल्य नहीं लौटाते हैं और साइड इफेक्ट नहीं होते हैं? या मुझे एक अलग तरीके से परीक्षण को फिर से लिखना चाहिए? या बस एक टिप्पणी डाल रहा हूँ कि मैं क्या कर रहा हूँ?



11
पैदाइशी बिंदु, लेकिन अगर आपके पास एक ऐसा फ़ंक्शन है जो कोई तर्क नहीं लेता है (एक selfसंदर्भ के लिए सहेजें ) और कोई परिणाम नहीं देता है, तो यह शुद्ध कार्य नहीं है।
डेविड अर्नो

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

@DavidArno अधिक पांडित्यपूर्ण बिंदु, आपके पास "कुछ भी नहीं" विधि हो सकती है (यह मानते हुए कि "कोई परिणाम नहीं देता है" की व्याख्या "रिटर्न एक इकाई प्रकार" के रूप में की जाती है जिसे voidकई भाषाओं में कहा जाता है और इसमें मूर्खतापूर्ण नियम होते हैं।) वैकल्पिक रूप से, आपके पास एक अनंत हो सकता है। लूप (जो "रिटर्न नॉट रिजल्ट" तब भी काम करता है " वास्तव में इसका मतलब है कि कोई परिणाम नहीं मिलता है।
डेरेक एल्किंस ने एसई

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

जवाबों:


21

अधिकांश परीक्षण ढाँचों में " expect(() => {}).not.toThrow();डोन्ट थ्रो" के लिए एक स्पष्ट दावा है, जैसे जैस्मीन के पास और nnnit और दोस्तों में से एक भी है।


1
और अगर परीक्षण ढांचे में ऐसा जोर नहीं है, तो स्थानीय विधि बनाना हमेशा संभव होता है, जो बिल्कुल वही काम करता है, जिससे कोड आत्म-व्याख्यात्मक हो जाता है। अच्छा विचार।
आर्सेनी मूरज़ेंको

7

यह दृढ़ता से उपयोग की जाने वाली भाषा और रूपरेखा पर निर्भर करता है। के संदर्भ में बोलते हुए NUnit, Assert.Throws(...)विधियाँ हैं। आप उन्हें एक मेमना विधि दे सकते हैं:

Assert.Throws(() => rangeValidator.EnsureValid(-5))

जिसे भीतर निष्पादित किया जाता है Assert.Throws। लैम्ब्डा को कॉल करने की संभावना सबसे अधिक एक try { } catch { }ब्लॉक द्वारा लपेटी जाएगी और यदि अपवाद पकड़ा जाता है, तो दावा विफल हो जाता है।

यदि आपकी रूपरेखा इन साधनों को प्रदान नहीं करती है, तो आप इसे कॉल कर सकते हैं, अपने आप से कॉल को लपेटकर (मैं C # में लिख रहा हूं):

// assert that the method does not fail
try
{
    rangeValidator.EnsureValid(50);
}
catch(Exception e)
{
    Assert.IsTrue(false, $"Exception: {e.Message}");
}

// assert that the method does fail
try
{
    rangeValidator.EnsureValid(50);
    Assert.IsTrue(false, $"Method is expected to throw an exception");
}
catch(Exception e)
{
}

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

संपादित करें

जैसा कि डॉक ब्राउन ने टिप्पणियों में बताया, मुद्दा यह इंगित करने के लिए नहीं है कि विधि फेंकता है, लेकिन यह फेंक नहीं करता है। NUnit में उसके लिए भी एक जोर है

Assert.DoesNotThrow(() => rangeValidator.EnsureValid(-5))

1

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

जैसा कि आप अन्य उत्तरों में देख सकते हैं, कुछ और कोड को अधिक जटिल और बरबाद कर देता है। वहाँ टिप्पणी के साथ, अन्य प्रोग्रामर परीक्षण के इरादे को जानेंगे।

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


1

आप यह भी दावा कर सकते हैं कि कुछ तरीकों को ठीक से (या नहीं बुलाया) कहा जाता है।

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

public void SendEmail(User user)
     ... construct email ...
     _emailSender.Send(email);

आपके परीक्षण में:

emailSenderMock.VerifyIgnoreArgs(service =>
    service.Send(It.IsAny<Email>()),
    Times.Once
);
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.