2009-07-02 15 views
5

तो मैं एक विधि के साथ एक वर्ग के रूप में निम्नानुसार है:मैं कैसे इकाई परीक्षण कैशिंग की तरह एक कार्यान्वयन विस्तार

public class SomeClass 
{ 
    ... 

    private SomeDependency m_dependency; 

    public int DoStuff() 
    { 
     int result = 0; 
     ... 
     int someValue = m_dependency.GrabValue(); 
     ... 
     return result; 
    } 
} 

और मैं तय कर लिया है कि m_dependency.GrabValue() हर बार फोन करने के लिए करने के बजाय, मैं वास्तव में कैश करना चाहते हैं मेमोरी में मूल्य (यानी इस वर्ग में) क्योंकि हम हर बार वही मूल्य प्राप्त करने जा रहे हैं (निर्भरता बंद हो जाती है और उस तालिका से कुछ डेटा पकड़ लेती है जो शायद ही कभी बदलती है)।

हालांकि मैं एक इकाई परीक्षण में इस नए व्यवहार का वर्णन करने की कोशिश कर रहा हूं, हालांकि मैंने समस्याओं में भाग लिया है। मैं निम्नलिखित (मैं RhinoMocks साथ NUnit उपयोग कर रहा हूँ) की कोशिश की है:

[Test] 
public void CacheThatValue() 
{ 
    var depend = MockRepository.GeneraMock<SomeDependency>(); 

    depend.Expect(d => d.GrabValue()).Repeat.Once().Return(1); 

    var sut = new SomeCLass(depend); 
    int result = sut.DoStuff(); 
    result = sut.DoStuff(); 
    depend.VerifyAllExpectations(); 
} 

हालांकि यह काम नहीं करता है; यह परीक्षण कार्यक्षमता में किसी भी बदलाव को शुरू किए बिना भी गुजरता है। मैं क्या गलत कर रहा हूं?

+2

प्रश्न पूछने के लिए खेद है, लेकिन कुछ ऐसा परीक्षण क्यों करें जो कार्यान्वयन विस्तार है? – Robert

उत्तर

5

मैं डॉट (आईएनजी) सामग्री के लिए ऑर्थोगोनल के रूप में कैशिंग देखता हूं। मुझे विधि के बाहर कैशिंग तर्क को खींचने का कोई तरीका मिलेगा, या तो कुछ निर्भरता को बदलकर या इसे किसी भी तरह लपेटकर (अब मेरे पास लैम्ब्डा एक्सप्रेशन - यम के आस-पास कैशिंग क्लास के लिए एक अच्छा विचार है)।

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

यूनिट परीक्षणों को कार्यान्वयन का परीक्षण नहीं किया जाना चाहिए, उन्हें व्यवहार का परीक्षण करना चाहिए। साथ ही, परीक्षण के अधीन विषय में व्यवहार का संकुचित रूप से परिभाषित सेट होना चाहिए।

अपने प्रश्न का उत्तर देने के लिए, आप एक डायनामिक मॉक का उपयोग कर रहे हैं और डिफ़ॉल्ट व्यवहार किसी भी कॉल को कॉन्फ़िगर नहीं किया गया है। अतिरिक्त कॉल सिर्फ "0" लौट रहे हैं।

depend.Expect(d => d.GrabValue()).Repeat.Once().Return(1); 
depend.Expect(d => d.GrabValue()).Repeat.Never(); 

आप इसे ठीक से काम करने के लिए रिकॉर्ड/पुनरावृत्ति मोड में प्रवेश करने की आवश्यकता हो सकती: आप एक उम्मीद है कि कोई अधिक कॉल निर्भरता पर किया जाता है स्थापित करने के लिए की जरूरत है।

+0

अच्छा बिंदु: "यूनिट परीक्षणों को कार्यान्वयन का परीक्षण नहीं किया जाना चाहिए, उन्हें व्यवहार का परीक्षण करना चाहिए। साथ ही, परीक्षण के अधीन विषय में व्यवहार का संकुचित रूप से परिभाषित सेट होना चाहिए।" यह मेरे प्रश्न का उत्तर देता है (जैसा कि मेरे प्रश्न पर रॉबर्ट की टिप्पणी करता है) – jpoh

4

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

तो परीक्षण - और गंध - हमें बता रहे हैं कि हमें एक नई कक्षा की आवश्यकता है। टेस्ट-संचालित डिजाइन। क्या यह अच्छा नहीं है?

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