2008-08-09 22 views
55

Mocking sealed classes काफी दर्द हो सकता है। मैं वर्तमान में इसे संभालने के लिए Adapter pattern का पक्ष लेता हूं, लेकिन केवल कुछ अजीब लगता है।आप एक मुहरबंद कक्षा का नकल कैसे करते हैं?

तो, सीलबंद कक्षाओं का नकल करने का सबसे अच्छा तरीका क्या है?

जावा उत्तर से अधिक हैं। असल में, मुझे उम्मीद है कि जावा समुदाय इस समय से निपट रहा है और पेशकश करने का एक बड़ा सौदा है।

लेकिन यहाँ नेट राय में से कुछ हैं:

+0

नकली मत बनो! [इसके बजाए संरचना का प्रयोग करें] (http://stackoverflow.com/a/891820/274502)। – cregox

उत्तर

6

अंगूठे का मेरा सामान्य नियम है कि वस्तुओं है कि मैं नकली करने की जरूरत है एक आम इंटरफेस भी होना चाहिए। मुझे लगता है कि यह सही डिजाइन-वार है और परीक्षणों को बहुत आसान बनाता है (और यदि आप टीडीडी करते हैं तो आमतौर पर आपको क्या मिलता है)। इसके बारे में अधिक Google परीक्षण ब्लॉग latest post में पढ़ा जा सकता है (बिंदु 9 देखें)।

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

+19

मैं तर्क दूंगा कि आपके पास एक वर्ग को सील करने के लिए * अच्छा * होना चाहिए। कक्षा खोलने का मतलब है कि आपको इस बारे में सोचना होगा कि इसका उपयोग विरासतकर्ताओं द्वारा कैसे किया जाएगा, जो वर्ग (वर्चुअल, संरक्षित गुण या निजी सदस्य चर, इत्यादि) के सभी कोडों के बारे में निर्णय की बाढ़ उत्पन्न करता है। यह * कठिन * विरासत के लिए एक कक्षा को सही ढंग से डिजाइन करने के लिए। आप सिर्फ विस्तार के लिए कक्षा का विस्तार नहीं कर पाएंगे; व्युत्पन्न का मतलब मॉडल की समस्या के लिए कुछ विशिष्ट होना चाहिए। अन्यथा, इसके बजाए संरचना का पक्ष लें। –

+2

ब्रायन - तो आप फिर एक मुहरबंद वर्ग का नकल कैसे करेंगे? मैं सैद्धांतिक दृष्टिकोण से आपसे सहमत हूं, लेकिन यदि आप अपनी मुहरबंद कक्षा पर निर्भर कुछ लिखते हैं तो आपके परीक्षण मुहरबंद वर्ग पर भी निर्भर करते हैं। –

+4

@abyx: दुर्भाग्यवश, यह हमेशा डेवलपर की पसंद नहीं है कि कक्षा को सील कर दिया गया हो या नहीं। ले लो, उदाहरण के लिए, ASP.NET में System.Web.HttpServerUtility ... – chiccodoro

1

वहाँ एक अंतरफलक से एक सील बंद वर्ग को लागू करने के लिए एक रास्ता है ... और इसके बजाय इंटरफ़ेस नकली? मुझ में

कुछ का मानना ​​है कि सील कक्षाएं होने पहली जगह में गलत है, लेकिन है कि सिर्फ मुझे :)

+2

मुझे लगता है कि मुहरबंद कक्षाएं बहुत अच्छी हैं ... समस्या परीक्षण कर रही है। यह बदबू आ रही है कि हमें .NET परियोजनाओं के परीक्षण में सीमाओं के कारण अपना पूरा डिज़ाइन बदलना होगा। कई मामलों में डीआई इस तथ्य को पाने के लिए बस एक तरीका है कि स्थिर वर्ग/विधियों का परीक्षण करना मुश्किल है। –

18

.NET के लिए, आप TypeMock जैसे कुछ का उपयोग कर सकते हैं, जो प्रोफाइलिंग एपीआई का उपयोग करता है और आपको लगभग किसी भी चीज़ पर कॉल करने की अनुमति देता है।

+7

+1। सही उपकरण का प्रयोग करें। औजारों को आपको निर्देशित न करें कि आपको चीजों को कैसे करना चाहिए। एपीआई लोगों के लिए हैं, उपकरण के लिए नहीं - उन्हें इस तरह डिजाइन करें। डी और इंटरफेस और पूर्ण डिकूप्लिंग का उपयोग करें जहां यह समझ में आता है, न सिर्फ इसलिए कि आपको परीक्षण उपकरणों के लिए इसकी आवश्यकता होती है। –

+2

पावेल - समस्या यह है कि .NET में "दाएं" तरीके आमतौर पर 'परीक्षण के लिए टाइपमॉक का उपयोग करें' के पथ को नीचे ले जाता है। एक पथ के बाद जहां केवल एक परीक्षण उपकरण उपलब्ध है, वह भी अच्छा प्रतीत नहीं होता है। –

+5

कुछ लोग टेस्ट फ्रेमवर्क के लिए $ 80 प्रति माह का भुगतान करना पसंद नहीं कर सकते हैं। –

4

टाइपमॉक के साथ समस्या यह है कि यह खराब डिजाइन को बहाना देती है। अब, मुझे पता है कि यह अक्सर किसी और का खराब डिज़ाइन है जो इसे छुपा रहा है, लेकिन इसे आपकी विकास प्रक्रिया में अनुमति देने से आपके स्वयं के खराब डिज़ाइनों को अनुमति मिल सकती है।

मुझे लगता है कि यदि आप एक मॉकिंग फ्रेमवर्क का उपयोग करने जा रहे हैं, तो आपको पारंपरिक एक (मोक की तरह) का उपयोग करना चाहिए और अनावश्यक चीज़ के आस-पास एक अलगाव परत बनाना चाहिए, और इसके बजाय अलगाव परत का नकल करना चाहिए।

+11

दृष्टि में सब कुछ पर इंटरफेस को थप्पड़ मारना सिर्फ इसलिए कि आपको अपने परीक्षण उपकरणों की कमियों की वजह से उनकी आवश्यकता है क्योंकि खराब डिजाइन नहीं है। असल में, काफी विपरीत - यह _sane_ डिज़ाइन है जो डिज़ाइन के बारे में है, न कि आपके टूल्स के अनुरूप। मैं कसम खाता हूं, कभी-कभी मुझे लगता है कि टीडीडी जितना प्रायः व्यावहारिक रूप से अभ्यास किया जाता है उसे वास्तव में "उपकरण-संचालित डिजाइन" कहा जाना चाहिए। Http://weblogs.asp.net/rosherove/archive/2008/01/17/is-typemock-too-powerful-will-it-kill-design-for-testability भी देखें।एएसपीएक्स –

+0

पावेल - क्या आपके पास TypeMock के अलावा कोई अन्य टूल है जो इस प्रकार के परीक्षण प्रदान कर सकता है? सैनी डिज़ाइनों के साथ निर्मित परीक्षण कक्षाएं (उदाहरण के लिए स्थैतिक तरीकों का उपयोग करना, कोड में नई कॉल, इंटरफेस को सीमित करना जहां कई कार्यान्वयन की आवश्यकता है, आदि) परीक्षण के लिए असंभव के बगल में होते हैं। –

+1

मैं यहां ब्रैड से सहमत हूं। नकली वस्तु बनाना एक तात्पर्य है कि आप उस प्रकार के सार्वजनिक व्यवहार का परीक्षण कर रहे हैं। यही है, आप विशेष रूप से कह रहे हैं, "मुझे इस वस्तु के सार्वजनिक एपीआई को एक निश्चित तरीके से व्यवहार करने की आवश्यकता है।" यह व्यवहार * स्वतंत्र * है हालांकि कहा गया एपीआई लागू किया गया है। इसका मतलब है कि आपके पास पहले से परिभाषित (हालांकि अंतर्निहित) अमूर्तता है जिसे एक निश्चित तरीके से व्यवहार करने की आवश्यकता है। एक स्थिर प्रकार प्रणाली में, यह एक अमूर्त प्रकार बनाकर स्पष्ट किया जाना चाहिए। –

1

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

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

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

अधिक जानकारी के लिए, कृपया this page देखें।

4

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

यह भी मेरी निर्भरताओं को लंबे समय तक स्विच करना आसान बनाता है।

1

एक सीलबंद वर्ग का नकल करना पूरी तरह से उचित है क्योंकि कई ढांचे वर्गों को सील कर दिया गया है।

मेरे मामले में मैं नकली करने की कोशिश कर रहा हूं .Net's MessageQueue क्लास ताकि मैं अपने सुंदर अपवाद हैंडलिंग तर्क को टीडीडी कर सकूं।

अगर किसी के पास "गैर-अतिव्यापी सदस्य पर अमान्य सेटअप" के संबंध में मोक की त्रुटि को दूर करने के तरीके पर विचार है, तो कृपया मुझे बताएं।

कोड:

[TestMethod] 
    public void Test() 
    { 
     Queue<Message> messages = new Queue<Message>(); 
     Action<Message> sendDelegate = msg => messages.Enqueue(msg); 
     Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate = 
      (v1, v2) => 
      { 
       throw new Exception("Test Exception to simulate a failed queue read."); 
      }; 

     MessageQueue mockQueue = QueueMonitorHelper.MockQueue(sendDelegate, receiveDelegate).Object; 
    } 
    public static Mock<MessageQueue> MockQueue 
       (Action<Message> sendDelegate, Func<TimeSpan, MessageQueueTransaction, Message> receiveDelegate) 
    { 
     Mock<MessageQueue> mockQueue = new Mock<MessageQueue>(MockBehavior.Strict); 

     Expression<Action<MessageQueue>> sendMock = (msmq) => msmq.Send(It.IsAny<Message>()); //message => messages.Enqueue(message); 
     mockQueue.Setup(sendMock).Callback<Message>(sendDelegate); 

     Expression<Func<MessageQueue, Message>> receiveMock = (msmq) => msmq.Receive(It.IsAny<TimeSpan>(), It.IsAny<MessageQueueTransaction>()); 
     mockQueue.Setup(receiveMock).Returns<TimeSpan, MessageQueueTransaction>(receiveDelegate); 

     return mockQueue; 
    } 
+0

मुझे एक समाधान मिला है और यहां पोस्ट किया गया है: http://www.dotnetmonkey.net/post/Hard-to-Moq.aspx –

13

मुझे विश्वास है कि Moles, माइक्रोसॉफ्ट रिसर्च से, आप ऐसा कर सकते हैं। मोल्स पृष्ठ से:

मोल्स किसी भी नेट सील प्रकार में गैर आभासी/स्थिर उपाय अपना सकते हैं विधि, चक्कर के लिए इस्तेमाल किया जा सकता है।

अद्यतन: वहाँ एक नया ढांचा "नकली" आगामी वी.एस. 11 रिलीज में है कि मोल्स को बदलने के लिए डिज़ाइन किया गया है कहा जाता है:

Fakes Framework in Visual Studio 11 मोल्स & स्टब्स की अगली पीढ़ी है, और अंततः इसे बदल देगा। मोल्स से नकली अलग है, हालांकि, मोल्स से फेक्स तक जाने के लिए आपके कोड में कुछ संशोधन की आवश्यकता होगी। इस प्रवासन के लिए एक गाइड बाद की तारीख में उपलब्ध होगा।

आवश्यकताओं: दृश्य स्टूडियो 11 परम, नेट 4,5

1

अपने वर्तमान में केवल बीटा रिलीज में उपलब्ध है, मेरे मन में अपनी सार्थक रखते हुए नई Fakes framework (Visual Studio 11 के हिस्से के shim सुविधा लगता है बीटा रिलीज)।

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

व्यक्तिगत रूप से मैं ड्रॉइंग कॉन्टेक्स्ट जैसे सीलबंद ढांचे वर्गों पर विधियों का नकल करने के लिए इसका उपयोग कर रहा था।

2

मैं हाल ही में इस समस्या को पार कर गया और वेब पढ़ने/खोजने के बाद, ऐसा लगता है कि उपरोक्त वर्णित किसी अन्य टूल का उपयोग करने के अलावा चारों ओर कोई आसान तरीका नहीं है। या मैंने जो कुछ किया है, उसे संभालने का कच्चा:

  • कन्स्ट्रक्टर प्राप्त किए बिना सीलबंद कक्षा का उदाहरण बनाएं।
  • सिस्टम। रनटाइम। सिराइलाइजेशन। फॉर्मेटर सर्विसेज। गेटयूनिनिलाइज्ड ऑब्जेक्ट (इंस्टेंस टाइप); ।

  • प्रतिबिंब

  • YourObject.GetType() getProperty ("प्रॉपर्टी") के माध्यम से अपने गुण/क्षेत्रों के लिए असाइन मूल्यों

    setValue (डीटीओ, newValue, नल)।

  • YourObject.GetType()। GetField ("FieldName")। SetValue (dto, newValue);
+0

यह एकमात्र समाधान है जो किसी भी अतिरिक्त पुस्तकालयों को जोड़ने के बिना आंतरिक माइक्रोसॉफ्ट सामानों का मज़ाक उड़ाने के लिए समझ में आता है और काम करता है नकली की तरह - धन्यवाद! – Ben