एक फ़ंक्शन का परीक्षण करने के लिए यूनिट कैसे रणनीति पैटर्न को दर्शाया गया है?


10

अगर मेरे कोड में एक फंक्शन है जो इस प्रकार है:

class Employee{

    public string calculateTax(string name, int salary)
    {
        switch (name)
        {
            case "Chris":
                doSomething($salary);
            case "David":
                doSomethingDifferent($salary);
            case "Scott":
               doOtherThing($salary);               
       }
}

आम तौर पर मैं इसे फैक्ट्री क्लास और रणनीति पैटर्न का उपयोग करके प्लोमोर्फिज्म का उपयोग करने के लिए मना करूंगा:

public string calculateTax(string name)
{
    InameHandler nameHandler = NameHandlerFactory::getHandler(name);
    nameHandler->calculateTax($salary);
}

अब अगर मैं टीडीडी का उपयोग कर रहा था तो मेरे पास कुछ परीक्षण होंगे जो कि calculateTax()रिफैक्टरिंग से पहले मूल पर काम करते हैं ।

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

calculateTax_givenChrisSalaryBelowThreshold_Expect111(){}    
calculateTax_givenChrisSalaryAboveThreshold_Expect111(){}

calculateTax_givenDavidSalaryBelowThreshold_Expect222(){}   
calculateTax_givenDavidSalaryAboveThreshold_Expect222(){} 

calculateTax_givenScottSalaryBelowThreshold_Expect333(){}
calculateTax_givenScottSalaryAboveThreshold_Expect333(){}

रिफैक्टरिंग के बाद, मेरे पास एक फैक्ट्री क्लास NameHandlerFactoryऔर कम से कम 3 का कार्यान्वयन होगा InameHandler

मुझे अपने परीक्षणों को वापस करने के लिए कैसे आगे बढ़ना चाहिए? मैं के लिए इकाई परीक्षण को नष्ट करना चाहिए claculateTax()से EmployeeTestsऔर में से प्रत्येक के कार्यान्वयन के लिए एक टेस्ट वर्ग बनाने InameHandler?

क्या मुझे फैक्टरी क्लास का भी परीक्षण करना चाहिए?

जवाबों:


6

पुराने परीक्षण calculateTaxअभी सत्यापन के लिए ठीक हैं जो अभी भी उसी तरह काम करता है जैसा कि इसे करना चाहिए। हालाँकि, आपको इसके लिए कई परीक्षण मामलों की आवश्यकता नहीं है, केवल 3 (या शायद कुछ और, यदि आप भी अनपेक्षित मानों का उपयोग करके त्रुटि से निपटने के परीक्षण करना चाहते हैं name)।

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

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

अपडेट करें

के परीक्षणों के बीच कुछ दोहराव हो सकता है calculateTax(चलो उन्हें उच्च स्तरीय परीक्षण कहते हैं ) और व्यक्तिगत गणना रणनीतियों ( निम्न स्तर के परीक्षण ) के लिए परीक्षण - यह आपके कार्यान्वयन पर निर्भर करता है।

मुझे लगता है कि आपके परीक्षणों का मूल कार्यान्वयन विशिष्ट कर गणना के परिणाम का अनुमान लगाता है, यह स्पष्ट रूप से पुष्टि करता है कि विशिष्ट गणना रणनीति का उपयोग इसे बनाने के लिए किया गया था। यदि आप इस स्कीमा को रखते हैं, तो आपके पास वास्तव में दोहराव होगा। हालाँकि, @Kristof ने संकेत दिया कि आप उच्च स्तर के परीक्षण का उपयोग करके मॉक का भी उपयोग कर सकते हैं, केवल यह सत्यापित करने के लिए कि सही (मॉक) रणनीति का चयन किया गया था और उसके द्वारा चालान किया गया था calculateTax। इस मामले में उच्च और निम्न स्तर के परीक्षणों के बीच कोई दोहराव नहीं होगा।

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

क्या मुझे फैक्टरी क्लास का भी परीक्षण करना चाहिए?

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


मैंने अपने वास्तविक व्यावहारिक कोड के करीब बनाने के लिए कोड को थोड़ा संशोधित किया। अब salaryफ़ंक्शन के लिए एक दूसरा इनपुट calculateTax()जोड़ा गया था। इस तरह से मुझे लगता है कि मैं मूल फ़ंक्शन और रणनीति वर्ग के 3 कार्यान्वयन के लिए परीक्षण कोड की नकल कर रहा हूं।
सांगो

@Songo, कृपया मेरा अपडेट देखें।
पेर्ट टॉर्क

5

मैं यह कहकर शुरू करूंगा कि मैं TDD या यूनिट परीक्षण का कोई विशेषज्ञ नहीं हूं, लेकिन यहां बताया गया है कि मैं इसका परीक्षण कैसे करूंगा (मैं छद्म-प्रकार कोड का उपयोग करूंगा):

CalculateTaxDelegatesToNameHandler()
{
    INameHandlerFactory fakeNameHandlerFactory = Fake(INameHandlerFactory);
    INameHandler fakeNameHandler = Fake(INameHandler);

    A.Call.To(fakeNameHandlerFactory.getHandler("John")).Returns(fakeNameHandler);

    Employee employee = new Employee(fakeNameHandlerFactory);
    employee.CalculateTax("John");

    Assert.That.WasCalled(fakeNameHandler.calculateTax());
}

इसलिए मैं परीक्षण करूंगा कि calculateTax()कर्मचारी वर्ग की विधि सही तरीके से इसके NameHandlerFactoryलिए कहती है NameHandlerऔर फिर calculateTax()लौटाए गए तरीके को बुलाती है NameHandler


हममम तो आपका मतलब है कि मुझे परीक्षण को एक व्यवहार परीक्षण बनाना चाहिए (परीक्षण कुछ कार्यों को बुलाया गया था) और प्रत्यायोजित वर्गों पर मूल्य का दावा करना चाहिए?
सांगो

हां, मैं यही करूंगा। मैं वास्तव में NameHandlerFactory और NameHandler के लिए अलग-अलग परीक्षण लिखूंगा। जब आपके पास वे होते हैं, तो Employee.calculateTax()विधि में उनकी कार्यक्षमता का परीक्षण करने का कोई कारण नहीं होता है । जब आप एक नया NameHandler परिचय करते हैं, तो आपको अतिरिक्त कर्मचारी-परीक्षण जोड़ने की आवश्यकता नहीं होती है।
क्रिस्टोफ क्ले

3

आप एक वर्ग (कर्मचारी जो सब कुछ करता है) और वर्गों के 3 समूह बना रहा है: कारखाना, कर्मचारी (जिसमें सिर्फ एक रणनीति होती है) और रणनीतियाँ।

इसलिए परीक्षणों के 3 समूह बनाएं:

  1. अलगाव में कारखाने का परीक्षण करें। क्या यह इनपुट को सही तरीके से हैंडल करता है। जब आप अज्ञात में गुजरते हैं तो क्या होता है?
  2. अलगाव में कर्मचारी का परीक्षण करें। क्या आप एक मनमानी रणनीति निर्धारित कर सकते हैं और यह आपकी अपेक्षा के अनुरूप काम करता है? यदि कोई रणनीति या कारखाना सेट नहीं है तो क्या होगा? (यदि यह कोड में संभव है)
  3. अलगाव में रणनीतियों का परीक्षण करें। क्या प्रत्येक आपके द्वारा अपेक्षित रणनीति का प्रदर्शन करता है? क्या वे एक सुसंगत तरीके से विषम सीमा आदानों को संभालते हैं?

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


2

किसी भी कोड को लिखने से पहले, मैं एक कारखाने के लिए एक परीक्षण के साथ शुरू करूँगा। जरूरत के सामान की नकल करना मुझे अपने आप को लागू करने और usecases के बारे में सोचने के लिए मजबूर करेगा।

से पहले मैं एक कारखाने को लागू करूंगा और प्रत्येक कार्यान्वयन के लिए एक परीक्षण जारी रखूंगा और अंत में उन परीक्षणों के लिए खुद को लागू करूंगा।

अंत में मैं पुराने परीक्षणों को हटा दूंगा।


2

मेरी राय है कि आपको कुछ नहीं करना चाहिए, मतलब आपको कोई नई परीक्षा नहीं देनी चाहिए।

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

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

चाचा बॉब की एक बड़ी पोस्ट है, जो TDD का उपयोग करते समय इस समस्या के बारे में बिल्कुल बात करता है।

मुझे लगता है कि प्रत्येक अलग वर्ग का परीक्षण करने की प्रवृत्ति जो टीडीडी को मार रही है। टीडीडी की पूरी सुंदरता यह है कि आप डिजाइन योजनाओं को बढ़ाने के लिए परीक्षणों का उपयोग करते हैं और इसके विपरीत नहीं।

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