मैं एक्सटेंशन विधि का उपयोग करने के लिए Moq का उपयोग कैसे करूं?


87

मैं एक परीक्षण लिख रहा हूं जो एक विस्तार विधि के परिणामों पर निर्भर करता है, लेकिन मैं उस विस्तार पद्धति की भविष्य की विफलता कभी नहीं चाहता कि यह परीक्षण टूट जाए। उस परिणाम का मज़ाक उड़ाना स्पष्ट विकल्प लगता था लेकिन Moq एक स्थैतिक विधि (एक एक्सटेंशन विधि के लिए एक आवश्यकता) को ओवरराइड करने का एक तरीका प्रदान नहीं करता है । Moq.Protected और Moq.Stub के साथ एक समान विचार है, लेकिन वे इस परिदृश्य के लिए कुछ भी प्रस्तावित नहीं करते हैं। क्या मुझे कुछ याद आ रहा है या मुझे इस बारे में अलग तरीके से जाना चाहिए?

यहां एक तुच्छ उदाहरण दिया गया है जो सामान्य रूप से "गैर-अमान्य सदस्य पर अमान्य अपेक्षा" के साथ विफल होता है । यह एक विस्तार विधि का मजाक उड़ाने की जरूरत का एक बुरा उदाहरण है, लेकिन यह करना चाहिए।

public class SomeType {
    int Id { get; set; }
}

var ListMock = new Mock<List<SomeType>>();
ListMock.Expect(l => l.FirstOrDefault(st => st.Id == 5))
        .Returns(new SomeType { Id = 5 });

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


3
एक डुप्लिकेट यहां पाया जा सकता है: stackoverflow.com/questions/2295960/…
ओलिवर

6
यह सवाल उस एक साल से भी पुराना है। यदि दोहराव होता है, तो वह दूसरे रास्ते पर चला जाता है।
पितृ पक्ष

2
फिर भी 2019 में कोई उचित समाधान नहीं!
तनवीरअर्जेल

1
@TanvirArjel वास्तव में, कई वर्षों से आप JustMock को विस्तार विधियों का उपयोग करने के लिए उपयोग कर सकते हैं । और किसी भी अन्य विधि का मजाक उड़ाने जितना सरल है। यहाँ प्रलेखन के लिए एक कड़ी है: विस्तार के तरीके मॉकिंग
Mihail व्लादोव

जवाबों:


69

विस्तार विधियाँ भेस में सिर्फ स्थिर विधियाँ हैं। मॉक या राइनोमॉक्स जैसी नकली रूपरेखा केवल वस्तुओं के नकली उदाहरण बना सकती है, इसका मतलब है कि स्थिर तरीकों का मजाक उड़ाना संभव नहीं है।


68
@ Mendelt..Then एक इकाई एक विधि का परीक्षण कैसे करेगी जो आंतरिक रूप से एक विस्तार विधि है? संभावित विकल्प क्या हैं?
साईं अविनाश

@ बताइए, एक इकाई एक ऐसी पद्धति का परीक्षण कैसे करेगी जिसमें आंतरिक रूप से एक विस्तार विधि है? संभावित विकल्प क्या हैं?
अलेक्जेंडर

@Alexander मेरे पास एक ही सवाल था और फिर इसने इसका उत्तर कल्पनात्मक रूप से दिया : agooddayforscience.blogspot.com/2017/08/… -इस पर एक नज़र डालें, यह एक जीवन रक्षक है!
LTV

30

अगर आप एक्सटेंशन मेथड्स कोड को बदल सकते हैं तो टेस्ट करने में सक्षम होने के लिए इसे इस तरह से कोड कर सकते हैं:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

public static class MyExtensions
{
    public static IMyImplementation Implementation = new MyImplementation();

    public static string MyMethod(this object obj)
    {
        return Implementation.MyMethod(obj);
    }
}

public interface IMyImplementation
{
    string MyMethod(object obj);
}

public class MyImplementation : IMyImplementation
{
    public string MyMethod(object obj)
    {
        return "Hello World!";
    }
}

तो एक्स्टेंशन के तरीके कार्यान्वयन इंटरफ़ेस के चारों ओर केवल एक आवरण है।

(आप विस्तार विधियों के बिना सिर्फ क्रियान्वयन वर्ग का उपयोग कर सकते हैं, जो कि वाक्यगत शर्करा के प्रकार हैं।)

और आप कार्यान्वयन इंटरफ़ेस को मॉक कर सकते हैं और इसे एक्सटेंशन क्लास के कार्यान्वयन के रूप में सेट कर सकते हैं।

public class MyClassUsingExtensions
{
    public string ReturnStringForObject(object obj)
    {
        return obj.MyMethod();
    }
}

[TestClass]
public class MyTests
{
    [TestMethod]
    public void MyTest()
    {
        // Given:
        //-------
        var mockMyImplementation = new Mock<IMyImplementation>();

        MyExtensions.Implementation = mockMyImplementation.Object;

        var myClassUsingExtensions = new MyClassUsingExtensions();

        // When:
        //-------
        var myObject = new Object();
        myClassUsingExtensions.ReturnStringForObject(myObject);

        //Then:
        //-------
        // This would fail because you cannot test for the extension method
        //mockMyImplementation.Verify(m => m.MyMethod());

        // This is success because you test for the mocked implementation interface
        mockMyImplementation.Verify(m => m.MyMethod(myObject));
    }
}

इसके लिए आपको बहुत धन्यवाद। यह बेहद उपयोगी था और मुझे परीक्षण में कुछ बाधाओं पर मिला।
डेरहाफिस्क

यह एक कमिटेड कमेंट है।
राज

16

मुझे पता है कि यह सवाल लगभग एक साल से सक्रिय नहीं है, लेकिन माइक्रोसॉफ्ट ने मोल्स नामक एक रूपरेखा को जारी किया ।

यहाँ कुछ ट्यूटोरियल दिए गए हैं:

  • DimeCasts.net
  • निकोलाई टिलमैन के ट्यूटोरियल


  • 14

    मैंने उन विस्तार विधियों के लिए एक आवरण वर्ग बनाया, जिनकी मुझे नकल करने की आवश्यकता थी।

    public static class MyExtensions
    {
        public static string MyExtension<T>(this T obj)
        {
            return "Hello World!";
        }
    }
    
    public interface IExtensionMethodsWrapper
    {
        string MyExtension<T>(T myObj);
    }
    
    public class ExtensionMethodsWrapper : IExtensionMethodsWrapper
    {
        public string MyExtension<T>(T myObj)
        {
            return myObj.MyExtension();
        }
    }
    

    फिर आप अपने परीक्षण में कोडर विधियों को अपने आईओसी कंटेनर के साथ मॉक कर सकते हैं।


    यह एक वर्कअराउंड है, जहाँ आप अपने कोड में अब एक्सटेंशन मेथड सिंटैक्स का उपयोग नहीं कर सकते हैं। लेकिन यह तब मदद करता है जब आप विस्तार के तरीकों को बदल नहीं सकते हैं।
    informatorius

    @informatorius उससे क्या मतलब है? अपने कोड में आप MyExtension वर्ग से MyExtension () का उपयोग करते हैं। अपने परीक्षणों में, आप पैरामीटर प्रदान करने वाले ExtensionMethodsWrapper () वर्ग से MyExtension () का उपयोग करते हैं।
    रंथोनिसेन

    यदि परीक्षण के तहत मेरी कक्षा MyExtension से MyExtension () का उपयोग करती है, तो मैं MyExtensions का मजाक नहीं उड़ा सकता। तो परीक्षण के तहत वर्ग IExtensionMethodsWrapper का उपयोग करना चाहिए ताकि यह नकली हो सके। लेकिन तब परीक्षण के तहत वर्ग अब विस्तार विधि वाक्यविन्यास का उपयोग नहीं कर सकता है।
    informatorius

    1
    यह ओपी का पूरा बिंदु है। यह उसके लिए एक समाधान है।
    रैंथोनिसेन

    4

    विस्तार के तरीकों के लिए मैं आमतौर पर निम्नलिखित दृष्टिकोण का उपयोग करता हूं:

    public static class MyExtensions
    {
        public static Func<int,int, int> _doSumm = (x, y) => x + y;
    
        public static int Summ(this int x, int y)
        {
            return _doSumm(x, y);
        }
    }
    

    यह _doSumm को काफी आसान इंजेक्षन करने की अनुमति देता है।


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

    @ स्टीफन को यकीन नहीं है कि इससे कैसे बचा जा सकता है। मैं कभी भी इस तरह की
    डांट

    0

    सबसे अच्छी बात यह है कि आप एक्सटेंशन पद्धति के लिए एक कस्टम कार्यान्वयन प्रदान कर सकते हैं, जैसे:

    [Fact]
    public class Tests
    {
        public void ShouldRunOk()
        {
            var service = new MyService(new FakeWebHostEnvironment());
    
            // Service.DoStuff() internally calls the SomeExtensionFunction() on IWebHostEnvironment
            // Here it works just fine as we provide a custom implementation of that interface
            service.DoStuff().Should().NotBeNull();
        }
    }
    
    public class FakeWebHostEnvironment : IWebHostEnvironment
    {
        /* IWebHostEnvironment implementation */
    
        public bool SomeExtensionFunction()
        {
            return false;
        }
    }
    
    हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
    Licensed under cc by-sa 3.0 with attribution required.