2010-08-21 8 views
24

हम हमारी सेवा कक्षाओं की इकाई परीक्षण करने के लिए Moq का उपयोग कर रहे हैं, लेकिन ऐसी स्थितियों का परीक्षण कैसे करें जहां एक सेवा विधि एक ही कक्षा के किसी अन्य सेवा विधि को कॉल करती है। मैंने वर्चुअल को बुलाए जाने वाले तरीके को सेट करने का प्रयास किया, लेकिन फिर भी यह पता नहीं लगा सका कि मोक में क्या करना है। उदाहरण के लिए:उसी कक्षा में वर्चुअल विधियों को ओवरराइड करने के लिए Moq का उपयोग

public class RenewalService : IRenewalService 
{ 
    //we've already tested this 
    public virtual DateTime? GetNextRenewalDate(Guid clientId) 
    { 
     DateTime? nextRenewalDate = null; 
     //...<snip> a ton of already tested stuff... 

     return nextRenewalDate; 
    } 

    //but want to test this without needing to mock all 
    //the methods called in the GetNextRenewalDate method 
    public bool IsLastRenewalOfYear(Renewal renewal) 
    { 
     DateTime? nextRenewalDate = GetNextRenewalDate(renewal.Client.Id); 
     if (nextRenewalDate == null) 
      throw new Exceptions.DataIntegrityException("No scheduled renewal date, cannot determine if last renewal of year"); 
     if (nextRenewalDate.Value.Year != renewal.RenewDate.Year) 
      return true; 
     return false; 
    } 
} 

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

मुझे एहसास है कि मैं एक नई कक्षा बना सकता हूं जो GetNextRenewalDate को ओवरराइड करता है और नई कक्षा का परीक्षण करता है, लेकिन क्या यह एक तरीका है कि मैं इसे आसान बनाने के लिए मोक का लाभ उठा सकता हूं?

उत्तर

41

आप शायद, इस परिदृश्य में आंशिक मजाक उपयोग कर सकते हैं, हालांकि अपने सभी तरीकों आभासी की आवश्यकता होगी:

var mock = new Moq.Mock<RenewalService>(); 
    mock.Setup(m => m.GetNextRenewalDate(It.IsAny<Guid>())).Returns(null); 
    mock.CallBase = true; 
    var results = mock.Object.IsLastRenewalOfYear(...); 
+0

यह काम करता प्रतीत होता है ... मुझे सबकुछ वर्चुअल बनाने की भी आवश्यकता नहीं थी (मैंने इसे ऊपर जैसा ही रखा)। – Andrew

+3

@ एंड्रयू। उपर्युक्त काम करता है क्योंकि 'मॉक.कॉलबेस == सत्य' का अर्थ यह है कि एक अपॉइंटमेंट जो सेटअप द्वारा मेल नहीं खाते हैं, अंतर्निहित कार्यान्वयन को कॉल करेंगे। इसलिए, 'IsLastRenewalOfYear' कार्यान्वयन को कॉल करेगा, क्योंकि यह वर्चुअल नहीं है, लेकिन' GetNextRenewalDate' 'शून्य' वापस कर देगा क्योंकि सेटअप हमेशा मिलान किया जाएगा। निम्न कोड काम करेगा, भले ही 'IsLastRenewalOfYear' ** ** वर्चुअल है। –

+1

हमने इसे कुछ अन्य स्थानों में भी इस्तेमाल किया, एक आकर्षण की तरह काम किया। धन्यवाद! – Andrew

0

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

संपादित करने से पहले:

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

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

यदि आप इस व्यवहार को अलग करने के लिए नकली वस्तुओं का उपयोग करना चाहते हैं, तो आपको इस वर्ग को थोड़ा अलग करना चाहिए। GetNextRenewalDate तर्क RenewalService ऑब्जेक्ट के बाहर रह सकता है।

तथ्य यह है कि आप इस समस्या में चल रहे हैं यह दिखा सकता है कि अभी तक एक सरल या अधिक बारीक अनाज डिजाइन है। "प्रबंधक" या "सेवा" जैसे नाम के साथ एक छोटी सी कंक्रीट वाली कक्षा ढूंढना प्रायः एक संकेत है कि आप अपने डिज़ाइन को छोटे वर्गों में विभाजित कर सकते हैं और इससे बेहतर पुन: प्रयोज्यता और रखरखाव प्राप्त कर सकते हैं।

+0

मुझे यकीन है कि अगर हमारे डिजाइन को तोड़ने इसे और अधिक पोषणीय बनाना होगा नहीं कर रहा हूँ .. अगर हम 5,000 कक्षाओं (लगभग वर्तमान में हमारे पास) से 10,000 कक्षाओं में गए, तो यह नेविगेट करना मुश्किल नहीं होगा। – Andrew

+0

डिज़ाइन को तोड़ने के लिए बस इसे एक विशिष्ट टूलसेट के भीतर अधिक टेस्ट करने योग्य बनाने के लिए एक बुरा विचार लगता है। इस पथ पर जाकर, आपको शायद ही कभी कक्षाओं के भीतर अन्य सार्वजनिक तरीकों को कॉल करने की विधियां होंगी। वह अच्छा डिजाइन कैसा है? –

+0

@ एंड्रयू, जेस: मुझे उनके ऐप या उसकी आवश्यकताओं को नहीं पता है, इसलिए मेरी सलाह लेने या छोड़ने में संकोच न करें। हां, इसे तोड़ने के लिए सिर्फ एक-विधि वर्ग मूर्खतापूर्ण है, लेकिन मेरी बाकी की सलाह अभी भी है। कई बार जब मैंने एक "प्रबंधक" या "सेवा" वर्ग देखा है, तो अवशोषण सही जगहों पर नहीं हैं। यदि ऐसा एक रिफैक्टर बनाया जाना था, तो अन्य वर्गों के तरीके यहां समाप्त हो सकते हैं, या ये विधियां अन्य कक्षाओं में समाप्त हो सकती हैं, जिससे यह वर्ग पूरी तरह से गायब हो जाता है। –

0
var mock = new Moq.Mock<RenewalService> { CallBase = true }; 
mock.Setup(m => m.GetNextRenewalDate(It.IsAny<Guid>())).Returns(null); 
var results = mock.Object.IsLastRenewalOfYear(...); 
संबंधित मुद्दे