moq

2010-01-19 14 views
7

का उपयोग करके तृतीय पक्ष कॉलबैक ईवेंट का मज़ाक उड़ाते हुए हम सी # में लिखे गए वर्कर क्लास के लिए यूनिट परीक्षण लिखने का प्रयास कर रहे हैं, जो मोक ऑब्जेक्ट्स को गतिशील रूप से बनाने के लिए moq का उपयोग करके किसी तृतीय पक्ष API (COM आधारित) को मॉक करता है। NUnit हमारी यूनिट परीक्षण ढांचा है।moq

यह तीसरा पक्ष घटक कुछ इंटरफेस लागू करता है, लेकिन घटनाओं का उपयोग करके हमारे कार्यकर्ता वर्ग में वापस कॉल करने की भी आवश्यकता है। हमारी योजना उन घटनाओं को अनुकरण करना था जो इस तीसरे पक्ष के घटक को उठा सकते हैं, और परीक्षण करें कि हमारे कार्यकर्ता वर्ग ने अपेक्षा के अनुसार संचालित किया था।

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

using Microsoft.Office.Interop.Word; 
using Moq; 
using NUnit.Framework; 
using SeparateNamespace; 

namespace SeparateNamespace 
{ 
    public interface LocalInterface_Event 
    { 
     event ApplicationEvents4_WindowActivateEventHandler WindowActivate; 
    } 
} 

namespace TestInteropInterfaces 
{ 
    [TestFixture] 
    public class Test 
    { 
     [Test] 
     public void InteropExample() 
     { 
      // from interop 
      Mock<ApplicationEvents4_Event> mockApp = new Mock<ApplicationEvents4_Event>(); 

      // identical code from here on... 
      bool isDelegateCalled = false; 

      mockApp.Object.WindowActivate += delegate { isDelegateCalled = true; }; 

      mockApp.Raise(x => x.WindowActivate += null, null, null); 

      Assert.True(isDelegateCalled); 
     } 

     [Test] 
     public void LocalExample() 
     { 
      // from local interface 
      Mock<LocalInterface_Event> mockApp = new Mock<LocalInterface_Event>(); 

      // identical code from here on... 
      bool isDelegateCalled = false; 

      mockApp.Object.WindowActivate += delegate { isDelegateCalled = true; }; 

      mockApp.Raise(x => x.WindowActivate += null, null, null); 

      Assert.True(isDelegateCalled); 
     } 
    } 
} 

कोई भी बता सकता है कि स्थानीय रूप से परिभाषित इंटरफ़ेस के लिए ईवेंट क्यों बढ़ाना है, लेकिन तीसरे पक्ष एपीआई (इस मामले में वर्ड) से आयात नहीं किया गया है?

मुझे एहसास है कि यह एक तथ्य है कि हम एक COM ऑब्जेक्ट (इंटरऑप असेंबली के माध्यम से) से बात कर रहे हैं लेकिन मुझे यकीन नहीं है कि समस्या के आसपास कैसे काम करना है।

+1

ऐसा प्रतीत होता है कि यह बग मोक v4.0 में तय किया गया है: http://code.google.com/p/moq/issues/detail?id=226 –

उत्तर

14

किसी ईवेंट की आंतरिक विधियों पर कॉल का पता लगाकर Moq 'इंटरसेप्ट्स' ईवेंट चलाएं। इन विधियों को add_ + घटना का नाम दिया गया है और 'विशेष' हैं कि वे गैर-मानक सी # विधियां हैं। इस प्रकार की घटनाओं गुण (get/set) की तरह कुछ हद तक कर रहे हैं और परिभाषित किया जा सकता:

event EventHandler MyEvent 
{ 
    add { /* add event code */ }; 
    remove { /* remove event code */ }; 
} 

यदि उपरोक्त घटना एक इंटरफेस पर परिभाषित किया गया था Moq'd होने के लिए, निम्नलिखित कोड है कि घटना को बढ़ाने के लिए इस्तेमाल किया जाएगा:

var mock = new Mock<IInterfaceWithEvent>; 
mock.Raise(e => e.MyEvent += null); 

यह सीधे घटनाओं के संदर्भ के लिए सी # में संभव नहीं है के रूप में, Moq को बीच में रोक अगर कॉल एक ईवेंट हैंडलर (जोड़ने के लिए उपरोक्त मामले में किया गया था सभी विधि मॉक और परीक्षणों पर कॉल को देखने के लिए, एक अशक्त हैंडलर है जोड़ा)। यदि ऐसा है, तो संदर्भ को अप्रत्यक्ष रूप से विधि के 'लक्ष्य' के रूप में प्राप्त किया जा सकता है।

add_ नाम से शुरू होने वाली विधि के रूप में प्रतिबिंब का उपयोग करके मोक द्वारा एक ईवेंट हैंडलर विधि का पता लगाया गया है और IsSpecialName ध्वज सेट के साथ। यह अतिरिक्त जांच घटनाओं से संबंधित विधि कॉल को फ़िल्टर करना है, लेकिन add_ से शुरू होने वाले नाम से फ़िल्टर करना है।

उदाहरण में, अवरुद्ध विधि को add_MyEvent कहा जाएगा और IsSpecialName ध्वज सेट होगा।

हालांकि, ऐसा लगता है कि इस interops में परिभाषित इंटरफेस के लिए पूरी तरह से सच के रूप में हालांकि ईवेंट हैंडलर विधि का नाम add_ के साथ शुरू होता है, यह नहींIsSpecialName ध्वज सेट करता है नहीं है,। ऐसा इसलिए हो सकता है क्योंकि वास्तविक 'विशेष' सी # घटनाओं के बजाय, निम्न-स्तर कोड (COM) फ़ंक्शंस के माध्यम से ईवेंट को मार्शल किया जा रहा है।

यह निम्न NUnit परीक्षण के साथ दिखाया जा सकता है (अपने उदाहरण का पालन करना):,

MethodInfo interopMethod = typeof(ApplicationEvents4_Event).GetMethod("add_WindowActivate"); 
MethodInfo localMethod = typeof(LocalInterface_Event).GetMethod("add_WindowActivate"); 

Assert.IsTrue(interopMethod.IsSpecialName); 
Assert.IsTrue(localMethod.IsSpecialName); 

इसके अलावा, एक अंतरफलक नहीं बनाया जा सकता है जो इंटरॉप इंटरफ़ेस से समस्या वैकल्पिक हल के लिए विरासत में के रूप में यह भी प्राप्त कर लेंगे marshalled add/remove विधियों।

यह समस्या Moq समस्या ट्रैकर यहाँ पर सूचना मिली थी: http://code.google.com/p/moq/issues/detail?id=226

अद्यतन:

जब तक यह Moq डेवलपर्स द्वारा संबोधित किया जाता है, केवल वैकल्पिक हल संशोधित करने के लिए प्रतिबिंब का उपयोग करने में हो सकता है इंटरफ़ेस जो Moq का उपयोग करने के उद्देश्य को हराने के लिए लगता है। दुर्भाग्यवश इस मामले के लिए 'अपने स्वयं के रोल' रोल करने के लिए बेहतर हो सकता है।

यह समस्या Moq 4.0 (अगस्त 2011 को जारी) में तय की गई है।

+0

धन्यवाद - moq बग रिपोर्ट पर नजर रखेगा । हमने तीसरे पक्ष एपीआई के आस-पास एक साधारण रैपर वर्ग लिखना समाप्त कर दिया, जिसे हम यूनिट परीक्षण का उपयोग करके नकल करने में सक्षम थे। –

+0

इसे ट्रैक करने के लिए धन्यवाद। मैं एक ही समस्या का सामना कर रहा था सिवाय इसके कि यह एफ # में परिभाषित इंटरफेस के साथ था। यह पता चला है कि वे IsSpecialName ध्वज को भी छोड़ देते हैं और इस बग में भी सिर चलाते हैं। – JaredPar

-1

क्या आप तृतीय पक्ष से COM इंटरफ़ेस को फिर से परिभाषित कर सकते हैं और moq के साथ इसका उपयोग कर सकते हैं।

ऐसा लगता है कि आपका इरादा बाहरी निर्भरता को दूर करना है और एमओक COMInterop असेंबली के साथ अच्छी तरह से खेल नहीं रहा है, तो आप इंटरऑप असेंबली से इच्छित इंटरफेस परिभाषाओं को खींचने और नकली परिभाषित करने में सक्षम होना चाहिए, अपने यूनिट परीक्षण

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