मॉक के साथ मॉकिंग एक्सटेंशन के तरीके


174

मैं एक आकर्षक इंटरफ़ेस है ...

public interface ISomeInterface
{
    void SomeMethod();
}

और मैं एक मिश्रण का उपयोग कर इस intreface बढ़ाया है ...

public static class SomeInterfaceExtensions
{
    public static void AnotherMethod(this ISomeInterface someInterface)
    {
        // Implementation here
    }
}

मेरे पास एक क्लास है जो इसे कॉल कर रहा है जिसे मैं परीक्षण करना चाहता हूं ...

public class Caller
{
    private readonly ISomeInterface someInterface;

    public Caller(ISomeInterface someInterface)
    {
        this.someInterface = someInterface;
    }

    public void Main()
    {
        someInterface.AnotherMethod();
    }
}

और एक परीक्षण जहां मैं इंटरफ़ेस को मॉक करना चाहूंगा और कॉल को एक्सटेंशन विधि में सत्यापित करूंगा ...

    [Test]
    public void Main_BasicCall_CallsAnotherMethod()
    {
        // Arrange
        var someInterfaceMock = new Mock<ISomeInterface>();
        someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable();

        var caller = new Caller(someInterfaceMock.Object);

        // Act
        caller.Main();

        // Assert
        someInterfaceMock.Verify();
    }

हालाँकि इस परीक्षण को चलाने से एक अपवाद उत्पन्न होता है ...

System.ArgumentException: Invalid setup on a non-member method:
x => x.AnotherMethod()

मेरा सवाल है, क्या मिक्सी कॉल को मॉक करने का एक अच्छा तरीका है?


3
मेरे अनुभव में, शब्द मिश्रण और विस्तार के तरीके अलग-अलग चीजें हैं। मैं मिक्सअप से बचने के लिए इस उदाहरण का उपयोग करूँगा: P
रुबेन बार्टलिंक

3
की डुप्लिकेट: stackoverflow.com/questions/562129/…
ओलिवर

जवाबों:


33

आप नकली ढांचे के साथ स्थैतिक विधि (इसलिए विस्तार विधि) को "सीधे" नहीं कर सकते। आप मोल्स ( http://research.microsoft.com/en-us/projects/pex/downloads.aspx ), Microsoft का एक निःशुल्क टूल जो एक अलग दृष्टिकोण लागू करता है, कोशिश कर सकते हैं । यहाँ उपकरण का वर्णन है:

मोल्स परीक्षण स्टब्स के लिए एक हल्का ढांचा है और .NET में detours है जो प्रतिनिधियों पर आधारित है।

मोल्स का उपयोग किसी भी .NET पद्धति को अलग करने के लिए किया जा सकता है, जिसमें गैर-आभासी / स्थिर तरीके सील किए गए प्रकारों में शामिल हैं।

आप किसी भी परीक्षण ढांचे के साथ मोल्स का उपयोग कर सकते हैं (यह उस बारे में स्वतंत्र है)।


2
मोल्स के अलावा, अन्य (गैर-मुक्त) मॉकिंग फ्रेमवर्क हैं जो ऑब्जेक्ट को मॉक करने के लिए .NET की प्रोफाइलर एपीआई का उपयोग करते हैं और इसलिए किसी भी कॉल को बदल सकते हैं। मुझे पता है कि दो टेलरिक के जस्टमॉक हैं और TypeMock अलगाने
मार्सेल गोसेलिन

6
सिद्धांत रूप में मोल्स अच्छे हैं, लेकिन मैंने तीन मुद्दों को पाया जब मैंने इसे ट्रायल किया जिसने मुझे इसका उपयोग करना बंद कर दिया ... 1) यह रेसपेरर न्निट रनर 2 में नहीं चलता है) आपको प्रत्येक स्टब्ड असेंबली 3 के लिए मैन्युअल रूप से एक मोल असेंबली बनाने की आवश्यकता है ) जब भी कोई स्टब्ड विधि बदलती है, तो आपको मैन्युअल रूप से एक तिल विधानसभा को फिर से बनाने की आवश्यकता होती है।
रसेल गिडिंग्स

26

मैंने इस समस्या को हल करने के लिए एक Wrapper का उपयोग किया है। एक आवरण ऑब्जेक्ट बनाएं और अपनी नकली विधि पास करें।

पॉल इरविन द्वारा यूनिट टेस्टिंग के लिए मॉकिंग स्टेटिक तरीके देखें , इसके अच्छे उदाहरण हैं।


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

2
मैंने एक छोटी सी लाइब्रेरी बनाई जो डैपर, डैपर.कंट्रिब और आईडीबीकोनेक्शन को लपेटती है। github.com/codeapologist/DataAbstractions.Dapper
आकर्षित सुमिडो

15

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

मैं आपकी विधि में सीधे कोड जोड़ने के रूप में एक एक्सटेंशन का उपयोग कर रहा था। इसका मतलब था कि मुझे विस्तार करने की बजाय खुद के विस्तार के बारे में बताने की जरूरत थी।


11

आप एक परीक्षण इंटरफ़ेस को मॉक कर सकते हैं जो वास्तविक से विरासत में मिला है और विस्तार विधि के समान हस्ताक्षर वाला एक सदस्य है।

फिर आप परीक्षण इंटरफ़ेस को मॉक कर सकते हैं, वास्तविक को मॉक में जोड़ सकते हैं और सेटअप में परीक्षण विधि को कॉल कर सकते हैं।

मॉक का आपका कार्यान्वयन तब आप जो भी विधि चाहते हैं उसे कॉल कर सकते हैं या बस उस विधि की जांच कर सकते हैं जिसे कहा जाता है:

IReal //on which some extension method is defined
{
    ... SomeRegularMethod(...);
}

static ExtensionsForIReal
{
    static ... SomeExtensionMethod(this IReal iReal,...);
}

ITest: IReal
{
    //This is a regular method with same name and signature as the extension without the "this IReal iReal" parameter
    ... SomeExtensionMethod(...);
}

var someMock = new Mock<ITest>();
Mock.As<IReal>(); //ad IReal to the mock
someMock.Setup(x => x.SomeExtensionMethod(...)).Verifiable(); //Calls SomeExtensionMethod on ITest
someMock.As<IReal>().Setup(x => x.SomeRegularMethod(...)).Verifiable(); //Calls SomeRegularMethod on IReal

दो इंटरफ़ेस का समर्थन करने वाले मॉक को कैसे लागू किया जाए , इस पोस्ट में Håvard S समाधान के लिए धन्यवाद । एक बार जब मैंने इसे पाया, तो इसे परीक्षण इंटरफ़ेस और स्थिर विधि के साथ अपनाना एक केक चलना था।


आप हमारे लिए ही नमूना हस्ताक्षर कृपया दिखा सकते हैं SomeNotAnExtensionMethodऔर SomeNotAnExtensionMethod? मुझे अब पता चला है कि एक इंटरफ़ेस के अंदर एक एक्सटेंशन विधि हस्ताक्षर कैसे बनाया जाए ...
पीटर सिसला

1
@Peter Csala: क्षमा करें यदि यह अस्पष्ट है। मैंने पोस्ट को स्पष्ट करने के लिए अपडेट किया और SomeNotAnExtensionMethod का नाम बदलकर SomeRegularMethod कर दिया।
pasx

के मामले में आप iRealपैरामीटर कैसे पास करते हैं ? यदि आप इसे पहले पैरामीटर के रूप में पास करते हैं तो आप सेटअप कैसे करते हैं? यह रनटाइम अपवाद का कारण बनेगा। SomeExtensionMethodITestSetup( x=> x.SomeExtensionMethod(x, ...)
पीटर सिसाला जूल

आप इसे पारित नहीं करते हैं। मॉक आईटीस्ट के दृष्टिकोण से इस पैरामीटर के बिना एक नियमित विधि शामिल है जिससे आप कोड में विस्तार विधि के लिए कॉल के हस्ताक्षर से मेल खाते हैं, इसलिए आपको यहां कभी भी एक आईआरएल प्राप्त नहीं होगा और किसी भी मामले में आईआरएल / आईटीएस्ट का कार्यान्वयन स्वयं नकली है। । यदि आप किसी के कुछ गुणों का उपयोग करना चाहते हैं, तो कुछ सम्‍मिलित मैथोड में आइल करें जो आपको मॉक में करना चाहिए जैसे: object _mockCache = whatever... `सेटअप (x => x.SomeExtensionMethod (...) .. कॉलबैक () => आप कर सकते हैं पहुँच _mockCache यहाँ);)
pasx

8

आप जस्टमॉक के साथ आसानी से एक विस्तार विधि का मजाक उड़ा सकते हैं । एपीआई सामान्य विधि के समान है। निम्नलिखित को धयान मे रखते हुए

public static string Echo(this Foo foo, string strValue) 
{ 
    return strValue; 
}

इस पद्धति को व्यवस्थित और सत्यापित करने के लिए निम्नलिखित का उपयोग करें:

string expected = "World";

var foo = new Foo();
Mock.Arrange(() => foo.Echo(Arg.IsAny<string>())).Returns(expected);

string result = foo.Echo("Hello");

Assert.AreEqual(expected, result);

यहाँ दस्तावेज़ीकरण की एक कड़ी भी दी गई है: एक्सटेंशन मेथड्स मॉकिंग


2

मैं आवरण (एडेप्टर पैटर्न) का उपयोग करना पसंद करता हूं, जब मैं ऑब्जेक्ट को स्वयं लपेट रहा हूं। मुझे यकीन नहीं है कि मैं एक एक्सटेंशन विधि को लपेटने के लिए उपयोग करूँगा, जो ऑब्जेक्ट का हिस्सा नहीं है।

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

    internal Func<IMyObject, string, object> DoWorkMethod
    {
        [ExcludeFromCodeCoverage]
        get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); }
        set { _DoWorkMethod = value; }
    } private Func<IMyObject, string, object> _DoWorkMethod;

तब आप वास्तविक विधि के बजाय फंक को कॉल करते हैं।

    public object SomeFunction()
    {
        var val = "doesn't matter for this example";
        return DoWorkMethod.Invoke(MyObjectProperty, val);
    }

अधिक पूर्ण उदाहरण के लिए, http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/ देखें।


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

-1

इसलिए यदि आप Moq का उपयोग कर रहे हैं, और एक्सटेंशन विधि के परिणाम का मजाक बनाना चाहते हैं, तो आप उपयोग कर सकते हैं SetupReturnsDefault<ReturnTypeOfExtensionMethod>(new ConcreteInstanceToReturn()) उस नकली वर्ग के उदाहरण पर जिसमें एक्सटेंशन विधि है जिसे आप मॉक करने का प्रयास कर रहे हैं।

यह सही नहीं है, लेकिन इकाई परीक्षण उद्देश्यों के लिए यह अच्छी तरह से काम करता है।


मेरा मानना ​​है कि यह SetReturnsDefault <T> () है
डेविड

वह ठोस उदाहरण कभी नहीं लौटाता है। सिर्फ कस्टम c # क्लास के मामले में अशक्त!
हेल्वर्ड
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.