Moq: एक नकली सेवा की विधि के लिए एक पैरामीटर को कैसे प्राप्त किया जाए


169

इस वर्ग की कल्पना करो

public class Foo {

    private Handler _h;

    public Foo(Handler h)
    {
        _h = h;
    }

    public void Bar(int i)
    {
        _h.AsyncHandle(CalcOn(i));
    }

    private SomeResponse CalcOn(int i)
    {
        ...;
    }
}

मो (क्यू) फू की एक परीक्षा में हैंडलर को सीकिंग, मैं कैसे जांच कर सकता हूं कि क्या Bar()बीत चुका है _h.AsyncHandle?


क्या आपका मतलब "AsyncHandle" (अतिरिक्त "n") था? और यदि आप एक मानक प्रकार है, तो क्या आप हैंडलर के लिए कोड पोस्ट कर सकते हैं, या पूरी तरह से योग्य टाइप नाम निर्दिष्ट कर सकते हैं?
ट्रूविल जूल

क्या आप जो सोच रहे हैं उसे दिखाने के लिए आप अपना कंकाल परीक्षण दिखा सकते हैं? जबकि मैं सराहना करता हूं कि आपकी तरफ से यह स्पष्ट है, हमारी तरफ से, यह किसी ऐसे व्यक्ति की तरह दिखता है जिसने लंबे समय तक सट्टा जवाब देने के बिना सवाल का जवाब देने के लिए समय नहीं लिया है।
रूबेन बार्टलिंक

1
न तो कोई फू है और न ही बार () और न ही ऐसा कुछ है। यह केवल कुछ डेमो कोड है जो स्थिति को दिखाती है कि मैं बिना किसी विशेष आकर्षण के विचलित हो रहा हूं। और मुझे सिर्फ जवाब मिला, मैं पाने की उम्मीद कर रहा था।
Jan

जवाबों:


283

आप Mock.Callback- विधि का उपयोग कर सकते हैं:

var mock = new Mock<Handler>();
SomeResponse result = null;
mock.Setup(h => h.AnsyncHandle(It.IsAny<SomeResponse>()))
    .Callback<SomeResponse>(r => result = r);

// do your test
new Foo(mock.Object).Bar(22);
Assert.NotNull(result);

यदि आप केवल पास किए गए तर्क पर कुछ सरल जांचना चाहते हैं, तो आप इसे सीधे भी कर सकते हैं:

mock.Setup(h => h.AnsyncHandle(It.Is<SomeResponse>(response => response != null)));

36
एक पक्ष ध्यान दें, यदि आपके पास अपने फ़ंक्शन के लिए कई तर्क हैं, तो आपको सभी प्रकार के सामान्य Callback<>()Moq विधि को निर्दिष्ट करने की आवश्यकता है । उदाहरण के लिए, यदि आपके पास विधि की परिभाषा है Handler.AnsyncHandle(string, SomeResponse), तो आपको आवश्यकता होगी /* ... */.Callback<string, SomeResponse>(r => result = r);। मुझे यह स्पष्ट रूप से कई जगहों पर नहीं मिला है, इसलिए मुझे लगा कि मैं इसे यहां जोड़ दूंगा।
फ्रैंक ब्रायस

12
यदि आपने @JavaJudt उत्तर नहीं देखा है तो बस @Frank को सही करना चाहते हैं। दो तर्क प्राप्त करने का सही तरीका है:/* ... */.Callback<string, SomeResponse>((s1, s2) => { str1 = s1; result = s2});
renatogbp

2
आप .Callback((string s1, SomeResponse s2) => /* stuff */ )
लैंबडा

1
क्या आप अंतर्निहित Capture.Inहेल्पर का संदर्भ शामिल करने के लिए अपनी प्रतिक्रिया अपडेट कर सकते हैं ?
काओ

29

गैमोर के जवाब ने मेरे लिए काम किया, लेकिन मुझे लगा कि मैं जॉन कारपेंटर की टिप्पणी पर विस्तार करूंगा क्योंकि मैं एक पैरामीटर से अधिक समाधान को ढूंढ रहा था। मुझे लगा कि इस पृष्ठ पर ठोकर खाने वाले अन्य लोग भी ऐसी ही स्थिति में हो सकते हैं। मुझे यह जानकारी Moq प्रलेखन में मिली ।

मैं Gamlor के उदाहरण का उपयोग करूँगा, लेकिन आइए दिखाते हैं कि AsyncHandle पद्धति में दो तर्क हैं: एक stringऔर एक SomeResponseवस्तु।

var mock = new Mock<Handler>();
string stringResult = string.Empty;
SomeResponse someResponse = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>()))
    .Callback<string, SomeResponse>((s, r) => 
    {
        stringResult = s;
        someResponse = r;
    });

// do your test
new Foo(mock.Object).Bar(22);
Assert.AreEqual("expected string", stringResult);
Assert.IsNotNull(someResponse);

मूल रूप से आपको बस It.IsAny<>()उपयुक्त प्रकार के साथ एक और जोड़ने की आवश्यकता है , Callbackविधि में एक और प्रकार जोड़ें , और लंबोदर अभिव्यक्ति को उपयुक्त रूप में बदलें।


22

कॉलबैक विधि निश्चित रूप से काम करेगी, लेकिन यदि आप बहुत सारे मापदंडों के साथ एक विधि पर कर रहे हैं तो यह थोड़ा वर्बोज़ हो सकता है। यहाँ कुछ ऐसा है जो मैंने बॉयलरप्लेट में से कुछ को हटाने के लिए उपयोग किया है।

var mock = new Mock<Handler>();

// do your test   
new Foo(mock.Object).Bar(22);

var arg = new ArgumentCaptor<SomeResponse>();
mock.Verify(h => h.AsyncHandle(arg.Capture()));
Assert.NotNull(arg.Value);

यहाँ तर्क के लिए स्रोत है:

public class ArgumentCaptor<T>
{
    public T Capture()
    {
        return It.Is<T>(t => SaveValue(t));
    }

    private bool SaveValue(T t)
    {
        Value = t;
        return true;
    }

    public T Value { get; private set; }
}

21

Gamlor का जवाब काम करता है, लेकिन इसे करने का एक और तरीका (और एक जिसे मैं परीक्षण में अधिक अभिव्यंजक मानता हूं) है ...

var mock = new Mock<Handler>();
var desiredParam = 47; // this is what you want to be passed to AsyncHandle
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once());

सत्यापित करना बहुत शक्तिशाली है, और समय के लिए इस्तेमाल होने लायक है।


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

1
मुझे पारित मूल्य को संग्रहीत करने की आवश्यकता है क्योंकि मुझे यह सत्यापित करने की आवश्यकता है कि सभी वस्तुओं का एक सेट जहां पारित हुआ।
MrFox

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

12

विकल्प भी Capture.Inसुविधा का उपयोग करने के लिए है moq। यह ओओटीबी moqसुविधा है जो संग्रह में तर्क कैप्चरिंग को सक्षम करता है।

//Arrange
var args = new List<SomeResponse>();
mock.Setup(h => h.AnsyncHandle(Capture.In(args)));

//Act
new Foo(mock.Object).Bar(22);

//Assert
//... assert args.Single() or args.First()

1
बहुत बढ़िया जवाब! मैं इस उत्तर को देखने तक Moq.Capture और Moq.CaptureMatch कक्षाओं से अनजान था। कैप्चर CallbackIMO का एक बेहतर विकल्प है । चूँकि आप पैरामीटर सूची में सीधे कैप्चर का उपयोग करते हैं, इसलिए यह विधि के पैरामीटर सूची को रीफ़ैक्टर करते समय बहुत कम समस्याएँ पैदा करता है, और इसलिए परीक्षण कम भंगुर बनाता है। कॉलबैक के साथ, आपको कॉलबैक के लिए उपयोग किए जाने वाले प्रकार के मापदंडों के साथ सेटअप में पास किए गए पैरामीटर को रखना होगा, और इससे निश्चित रूप से मुझे अतीत में समस्याएँ हुई हैं।
जस्टिन होलज़र

7

आप It.Is<TValue>()मिलान का उपयोग कर सकते हैं ।

var mock = new Mock<Handler>();
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null )));

2

यह भी काम करता है:

Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;

2

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

यहाँ एक gist है: https://gist.github.com/Jacob-McKay/8b8d41ebb9565f5fca23654fd944ac6b एक Moq (4.12) एक्सटेंशन के साथ जो मैं मॉक को पारित किए गए तर्कों के बारे में दावा करने के लिए एक अधिक घोषणात्मक तरीका देता हूं, बिना कमियां के। यहाँ वैरिफाई सेक्शन अभी जैसा दिखता है:

        mockDependency
            .CheckMethodWasCalledOnce(nameof(IExampleDependency.PersistThings))
            .WithArg<InThing2>(inThing2 =>
            {
                Assert.Equal("Input Data with Important additional data", inThing2.Prop1);
                Assert.Equal("I need a trim", inThing2.Prop2);
            })
            .AndArg<InThing3>(inThing3 =>
            {
                Assert.Equal("Important Default Value", inThing3.Prop1);
                Assert.Equal("I NEED TO BE UPPER CASED", inThing3.Prop2);
            });

मैं ठप्प हो जाऊंगा यदि Moq ने एक ऐसी सुविधा प्रदान की, जो घोषणा के रूप में एक ही चीज को पूरा करती है और विफलता अलगाव को प्रदान करती है। उंगलियों को पार कर!


1
यह मुझे पंसद है। Moq का सत्यापन प्रदर्शन करने के अधिकार के लिए xUnit के दावे के साथ प्रतिस्पर्धा करता है। यह सेटअप के Moq भाग पर सही नहीं लगता है। It.Is सुविधा सेटअप को गैर अभिव्यक्तियों का भी समर्थन करना चाहिए।
थॉमस

"Moq प्रदर्शन के अधिकार के लिए xUnit के दावे के साथ प्रतिस्पर्धा करता है" - अच्छी तरह से @Thomas ने कहा। मैं जोड़ूंगा कि यह प्रतियोगिता खो देगा। Moq आपको यह बताने में अच्छा है कि क्या एक मेल था, लेकिन विशिष्ट दावे आपको बेहतर जानकारी देते हैं। मेरे दृष्टिकोण का मुख्य दोष मापदंडों की सुरक्षा और व्यवस्था की जाँच को खोना है। मैं थोड़ी देर के लिए इस पर एक सुधार के लिए देख रहा हूँ, उम्मीद है कि वहाँ एक C # निनजा है जो एक साथ एक उदाहरण हैक कर सकते हैं! अन्यथा अगर मुझे कोई रास्ता मिल जाता है तो मैं इसे अपडेट कर दूंगा।
याकूब मैके
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.