মোক: একটি উপহাস পরিষেবাটির কোনও পদ্ধতিতে কীভাবে প্যারামিটারে যেতে হবে


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" (অতিরিক্ত "এন") বোঝাতে চেয়েছিলেন? এবং আপনি কি হ্যান্ডলারের জন্য কোড পোস্ট করতে পারেন, বা পুরোপুরি যোগ্যতাসম্পন্ন টাইপের নামটি যদি কোনও মানক টাইপ করেন তবে তা নির্দিষ্ট করতে পারেন?
ট্রুউইল

আপনি কী ভাবছেন তা দেখাতে আপনি নিজের কঙ্কালের পরীক্ষাটি প্রদর্শন করতে পারেন? যদিও আমি আপনার প্রশংসা করি এটি আপনার পক্ষ থেকে স্পষ্টতই, আমাদের পক্ষ থেকে, দেখে মনে হচ্ছে এমন একজন যিনি দীর্ঘ অনুমানমূলক উত্তর না দিয়েই প্রশ্নের উত্তর দেওয়ার জন্য সময় নেননি।
রুবেন বারটেলিংক

1
এখানে ফু বা বার নেই () বা এর মতো কিছুই নেই। অ্যাপ্লিকেশন সুনির্দিষ্টতা থেকে কোনও বিঘ্ন ছাড়াই আমি যে পরিস্থিতিটিতে আছি তা প্রদর্শন করার জন্য এটি কেবল কয়েকটি ডেমো কোড। এবং আমি ঠিক উত্তর পেয়েছি, আমি আশা করি।
জানুয়ারী

উত্তর:


283

আপনি মক.ক্যালব্যাক-পদ্ধতিটি ব্যবহার করতে পারেন:

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<>()মোখ পদ্ধতিতে সমস্ত ধরণের উল্লেখ করতে হবে । উদাহরণস্বরূপ, যদি আপনার পদ্ধতির সংজ্ঞা থাকে তবে আপনার Handler.AnsyncHandle(string, SomeResponse)প্রয়োজন হবে /* ... */.Callback<string, SomeResponse>(r => result = r);। আমি অনেক জায়গায় এটি স্পষ্টভাবে বলা হয়নি, তাই আমি অনুভব করেছি যে আমি এটি এখানে যুক্ত করব।
ফ্র্যাঙ্ক ব্রাইস

12
আপনি @ জাভাজড উত্তরটি না দেখলে স্রেফ @ ফ্র্যাঙ্কটি সংশোধন করতে চেয়েছিলেন। দুটি যুক্তি পাওয়ার সঠিক উপায় হ'ল:/* ... */.Callback<string, SomeResponse>((s1, s2) => { str1 = s1; result = s2});
রেন্যাটোগবিপি

2
আপনি কেবল ল্যাম্বডা এক্সপ্রেশনটিতে আর্গুমেন্টের প্রকারের ঘোষণা দিয়েও এটি অর্জন করতে পারেন:.Callback((string s1, SomeResponse s2) => /* stuff */ )
jb637

1
আপনি দয়া করে বিল্ট-ইন Capture.Inসহায়কটির কোনও রেফারেন্স অন্তর্ভুক্ত করার জন্য আপনার প্রতিক্রিয়াটি আপডেট করতে পারেন ?
cao

29

গ্যামলারের উত্তর আমার পক্ষে কাজ করেছে, কিন্তু আমি ভেবেছিলাম জন জন কার্পেন্টারের মন্তব্যটি প্রসারিত করব কারণ আমি একাধিক পরামিতি জড়িত একটি সমাধান খুঁজছিলাম। আমি অন্যান্য ভাবেন যারা এই পৃষ্ঠায় হোঁচট খায় একইরকম পরিস্থিতিতে থাকতে পারে। আমি মক ডকুমেন্টেশনে এই তথ্যটি পেয়েছি ।

আমি গ্যামলোর উদাহরণটি ব্যবহার করব, তবে আসানস্যান্ডহ্যান্ডল পদ্ধতিটি দুটি আর্গুমেন্ট গ্রহণ করে: একটি 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

গ্যামলারের উত্তরটি কাজ করে তবে এটি করার আরেকটি উপায় (এবং যা আমি পরীক্ষায় আরও অভিব্যক্তিক হিসাবে বিবেচনা করি) তা হ'ল ...

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());

যাচাই করা খুব শক্তিশালী এবং অভ্যাস করার জন্য সময় দেওয়ার মতো worth


15
যদি আপনি কেবলমাত্র কোনও প্যারামিটারের সাথে কোনও পদ্ধতি কল করা হয়েছে কিনা তা পরীক্ষা করতে চান তবে সেই পদ্ধতিরটি ঠিক। যে ক্ষেত্রে প্যারামিটারটি এখনও পরীক্ষার লেখার পয়েন্টে তৈরি হয়নি (যেমন প্রশ্নে ইউনিটটি অভ্যন্তরীণভাবে প্যারামিটার তৈরি করে), তারপরে কলব্যাক আপনাকে এটি ক্যাপচার এবং জিজ্ঞাসাবাদ করতে সক্ষম করে, তবে আপনার পন্থাটি এটি গ্রহণ করবে না।
মাইকেল

1
আমার পাস করা মান সংরক্ষণ করতে হবে কারণ আমার যাচাই করা দরকার যে সমস্ত বস্তুর সেটগুলি যেখানে গেছে।
মিঃফক্স

এছাড়াও, কখনও কখনও প্যারামিটারটি একটি সত্তা হয় এবং আপনি সত্তার প্রতিটি ক্ষেত্রের জন্য পৃথক সংস্থান চান। এটি করার সর্বোত্তম উপায় হ'ল ভেরিফাইড এবং ম্যাচার ব্যবহার না করে পরমকে ক্যাপচার করা।
কেভিন ওয়াং

12

বিকল্প Capture.Inবৈশিষ্ট্য ব্যবহার করা হয় moq। এটি OOTB 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
দুর্দান্ত উত্তর! এই উত্তর না পাওয়া পর্যন্ত আমি মো। ক্যাপচার এবং মো। ক্যাপচারম্যাচ ক্লাস সম্পর্কে অজানা ছিলাম। ক্যাপচার Callbackআইএমওর আরও ভাল বিকল্প । যেহেতু আপনি সরাসরি প্যারামিটার তালিকায় ক্যাপচার ব্যবহার করেন তাই কোনও পদ্ধতির প্যারামিটার তালিকাকে রিফ্যাক্টর করার সময় এটি ইস্যুগুলির তুলনায় অনেক কম ঝুঁকিপূর্ণ এবং তাই পরীক্ষাগুলি কম ভঙ্গুর করে তোলে। কলব্যাকের সাহায্যে আপনাকে কলআপের জন্য ব্যবহৃত ধরণের পরামিতিগুলির সাথে সেটআপে পাস করা প্যারামিটারগুলি রাখতে হবে এবং এটি অতীতে অবশ্যই আমার সমস্যার কারণ হয়েছিল।
জাস্টিন হলজার

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

অনেক ভাল উত্তর এখানে! আপনার নির্ভরতাগুলিতে বেশ কয়েকটি ক্লাস প্যারামিটারগুলি সম্পর্কে উত্তীর্ণ হওয়া পর্যন্ত আপনার মুখের বৈশিষ্ট্য-সেটটি বক্সের বাইরে রাখুন। আপনি যদি সেই পরিস্থিতিতে শেষ পর্যন্ত হন তবে এটির সাথে মোখ ভেরিফাই বৈশিষ্ট্যটি I আইটি ম্যাচাররা পরীক্ষার ব্যর্থতা আলাদা করার পক্ষে ভাল কাজ করে না এবং আর্গুমেন্টগুলি ক্যাপচার করার জন্য রিটার্নস / কলব্যাক উপায় আপনার পরীক্ষায় কোডের অপ্রয়োজনীয় লাইন যুক্ত করে (এবং দীর্ঘ পরীক্ষাগুলি আমার পক্ষে অযোগ্য।

এখানে একটি সংক্ষিপ্তসার রয়েছে: https://gist.github.com/Jacob-McKay/8b8d41ebb9565f5fca23654fd944ac6b একটি মো (৪.১২) এক্সটেনশন সহ আমি লিখেছিলাম যে পূর্ববর্তী বর্ণিত ত্রুটিগুলি ছাড়াই বিদ্রূপগুলিতে উত্থাপিত যুক্তিগুলি সম্পর্কে দৃ .়তার আরও বেশি উপায় প্রদান করে। যাচাইকরণ বিভাগটি এখন দেখতে কেমন:

        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);
            });

আমি যদি স্ট্রোকড হয়ে যাব যে মোক যদি এমন একটি বৈশিষ্ট্য সরবরাহ করে যা একই কাজ সম্পাদন করে যা ঘোষণা হিসাবে ঘোষণা করে এবং ব্যর্থতা বিচ্ছিন্নতা দেয় যা এটি করে। আঙ্গুলগুলি পার হয়ে গেল!


1
আমি এই পছন্দ। মোকারির যাচাই বাছাই সম্পাদনের কর্তৃত্বের জন্য xUnit এর আসরের সাথে প্রতিযোগিতা করে। সেটআপের Moq অংশে এটি ঠিক মনে হচ্ছে না। It.Is বৈশিষ্ট্য সেটআপ এছাড়াও অ এক্সপ্রেশন সমর্থন করা উচিত।
থমাস

"মোক্তা জরিমানা সম্পাদন করার কর্তৃত্বের জন্য xUnit এর সম্পদ সাথে প্রতিযোগিতা করে" - ভাল বলেছেন @ থমাস। আমি যোগ করব যে এটি প্রতিযোগিতা হারাবে। মেক ম্যাচিং কল ছিল কিনা তা আপনাকে জানাতে ভাল, তবে নির্দিষ্ট জোরগুলি আপনাকে আরও ভাল তথ্য দেয়। আমার পদ্ধতির মূল ত্রুটিটি পরামিতিগুলির সুরক্ষা এবং ক্রমের ক্রম হারাচ্ছে। আমি এটির জন্য কিছু সময়ের জন্য উন্নতি খুঁজছি, আশা করছি সেখানে একটি সি # নিনজা আছে যারা একসাথে উদাহরণ হ্যাক করতে পারে! অন্যথায় যদি আমি কোনও উপায় খুঁজে পাই তবে আমি এটি আপডেট করব।
জ্যাকব ম্যাকে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.