মোকের সাথে প্রথম এবং দ্বিতীয়বারের জন্য বিভিন্ন রিটার্নের মান রয়েছে


262

আমার এইরকম পরীক্ষা আছে:

    [TestCase("~/page/myaction")]
    public void Page_With_Custom_Action(string path) {
        // Arrange
        var pathData = new Mock<IPathData>();
        var pageModel = new Mock<IPageModel>();
        var repository = new Mock<IPageRepository>();
        var mapper = new Mock<IControllerMapper>();
        var container = new Mock<IContainer>();

        container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);

        repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageModel.Object);

        pathData.Setup(x => x.Action).Returns("myaction");
        pathData.Setup(x => x.Controller).Returns("page");

        var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);

        // Act
        var data = resolver.ResolvePath(path);

        // Assert
        Assert.NotNull(data);
        Assert.AreEqual("myaction", data.Action);
        Assert.AreEqual("page", data.Controller);
    }

গেটপেজবাইআরআইএল আমার ড্যাশবোর্ডপথ্রসলবারে দু'বার চলবে, আমি কীভাবে মোকে প্রথমবারের মতো নাল ফিরে আসতে এবং পৃষ্ঠা মোডেলকে বলতে পারি second দ্বিতীয়বার ওজবেক্ট করুন?

উত্তর:


452

MOQ এর সর্বশেষ সংস্করণ (4.2.1312.1622) সঙ্গে, আপনি সেটআপ ঘটনা একটা ক্রম ব্যবহার করতে পারেন SetupSequence । এখানে একটি উদাহরণ:

_mockClient.SetupSequence(m => m.Connect(It.IsAny<String>(), It.IsAny<int>(), It.IsAny<int>()))
        .Throws(new SocketException())
        .Throws(new SocketException())
        .Returns(true)
        .Throws(new SocketException())
        .Returns(true);

কলিং কানেক্ট কেবল তৃতীয় এবং পঞ্চম প্রয়াসেই সফল হবে অন্যথায় একটি ব্যতিক্রম ছুঁড়ে দেওয়া হবে।

সুতরাং আপনার উদাহরণের জন্য এটি ঠিক এমন কিছু হবে:

repository.SetupSequence(x => x.GetPageByUrl<IPageModel>(virtualUrl))
.Returns(null)
.Returns(pageModel.Object);

2
উত্তম উত্তর, একমাত্র সীমাবদ্ধতা হ'ল "সেটআপসেকেন্স" সুরক্ষিত সদস্যদের সাথে কাজ করে না।
চেসফোরনোন

7
হায়, SetupSequence()কাজ করে না Callback()। যদি কেবল এটিই হয়ে থাকে তবে কেউ "স্টেট মেশিন" ফ্যাশনে উপহাস পদ্ধতিতে কলগুলি যাচাই করতে পারে।
urig

@ স্ট্যাকুণ্ডফেরফ্লো SetupSequenceকেবলমাত্র দুটি কলের জন্য কাজ করে তবে যদি দুটি কলের বেশি প্রয়োজন হয় তবে আমি কী করতে পারি?
তানভীরআরজেল

@ তানভীরআরজেল, আপনি কী বলতে চাইছেন তা নিশ্চিত নন ... SetupSequenceএকটি নির্বিচার সংখ্যক কলের জন্য ব্যবহার করা যেতে পারে। প্রথম উদাহরণটি আমি পাঁচটি কলের ক্রম দিয়েছি।
stackunderflow

টুইটারে এটা আমার ভুল বোঝাবুঝি! হ্যাঁ! আপনি এটি সঠিক হিসাবে প্রত্যাশিত কাজ!
তানভীর আর্জেল

115

বিদ্যমান উত্তরগুলি দুর্দান্ত, তবে আমি ভেবেছিলাম যে আমি আমার বিকল্পটি ছুঁড়ে ফেলি যা কেবলমাত্র ব্যবহার করে System.Collections.Generic.Queueএবং উপহাসের কাঠামোর কোনও বিশেষ জ্ঞানের প্রয়োজন নেই - যেহেতু আমি এটি লেখার সময় কোনও ছিল না! :)

var pageModel = new Mock<IPageModel>();
IPageModel pageModelNull = null;
var pageModels = new Queue<IPageModel>();
pageModels.Enqueue(pageModelNull);
pageModels.Enqueue(pageModel.Object);

তারপর ...

repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(pageModels.Dequeue);

ধন্যবাদ। আমি ঠিক টাইপগুলি ঠিক করেছি যেখানে আমি পৃষ্ঠা মোডেলের পরিবর্তে পৃষ্ঠা মোডেলকে উপস্থাপন করছি b অবজেক্ট, তাই এখন এটিও তৈরি করা উচিত! :)
মো।

3
উত্তরটি সঠিক, কিন্তু মনে রাখবেন যে এই যদি আপনি একটি রাখার বিষয়ে কাজ করবে না যে Exceptionযেমন তুমি পারবে না Enqueueএটা। তবে SetupSequenceকাজ করবে (উদাহরণস্বরূপ @ স্ট্যাকউন্ডারফ্লো থেকে উত্তর দেখুন)।
হলভার্ড

4
ডিকুতে আপনাকে একটি প্রতিনিধি পদ্ধতি ব্যবহার করতে হবে। নমুনাটি যেভাবে লেখা হয়েছে তা সর্বদা সারিতে প্রথম আইটেমটি বারবার ফিরে আসবে কারণ সেটআপের সময় ডিকুইটি মূল্যায়ন করা হয়।
জেসন কোইন

7
সে একজন প্রতিনিধি। কোডটি যদি Dequeue()কেবলমাত্র পরিবর্তে থাকে তবে Dequeueআপনি সঠিক হবেন।
মো।

31

একটি কলব্যাক যোগ করা আমার পক্ষে কার্যকর হয়নি, আমি পরিবর্তে এই পদ্ধতিটি ব্যবহার করেছি http://haacked.com/archive/2009/09/29/moq-sequens.aspx এবং আমি এইরকম একটি পরীক্ষা দিয়ে শেষ করেছি:

    [TestCase("~/page/myaction")]
    [TestCase("~/page/myaction/")]
    public void Page_With_Custom_Action(string virtualUrl) {

        // Arrange
        var pathData = new Mock<IPathData>();
        var pageModel = new Mock<IPageModel>();
        var repository = new Mock<IPageRepository>();
        var mapper = new Mock<IControllerMapper>();
        var container = new Mock<IContainer>();

        container.Setup(x => x.GetInstance<IPageRepository>()).Returns(repository.Object);
        repository.Setup(x => x.GetPageByUrl<IPageModel>(virtualUrl)).ReturnsInOrder(null, pageModel.Object);

        pathData.Setup(x => x.Action).Returns("myaction");
        pathData.Setup(x => x.Controller).Returns("page");

        var resolver = new DashboardPathResolver(pathData.Object, repository.Object, mapper.Object, container.Object);

        // Act
        var data = resolver.ResolvePath(virtualUrl);

        // Assert
        Assert.NotNull(data);
        Assert.AreEqual("myaction", data.Action);
        Assert.AreEqual("page", data.Controller);
    }

29

আপনার মক অবজেক্ট সেট আপ করার সময় আপনি কলব্যাক ব্যবহার করতে পারেন। মোক উইকি ( http://code.google.com/p/moq/wiki/QuickStart ) থেকে উদাহরণটি দেখুন ।

// returning different values on each invocation
var mock = new Mock<IFoo>();
var calls = 0;
mock.Setup(foo => foo.GetCountThing())
    .Returns(() => calls)
    .Callback(() => calls++);
// returns 0 on first invocation, 1 on the next, and so on
Console.WriteLine(mock.Object.GetCountThing());

আপনার সেটআপটি দেখতে দেখতে এমন হতে পারে:

var pageObject = pageModel.Object;
repository.Setup(x => x.GetPageByUrl<IPageModel>(path)).Returns(() => pageObject).Callback(() =>
            {
                // assign new value for second call
                pageObject = new PageModel();
            });

1
আমি যখন এটি করি তখন আমি উভয় সময়ই নালু হয়ে যাব: var pageModel = new mock <IPageModel> (); আইপেজমোডেল মডেল = নাল; repository.Setup (x => x.GetPageByUrl <IPageModel> (path))। রিটার্নস (() => মডেল) .ক্যালব্যাক (())> মডেল = পেজমোডেল.অবজেক্ট;});
মারকাস

গেটপেজবিউআরলকে কি রিসলভারের মধ্যে দু'বার ডাকা হবে? পুনরায় সমাধান পদ্ধতি?
ড্যান

রেজলভপথে নীচের কোডটি অন্তর্ভুক্ত করেছে তবে এটি উভয় বারেই শূন্য var var foo2 = _repository.GetPageByUrl <IPageModel> (ভার্চুয়ালআরএল);
মারকাস

2
নিশ্চিত হয়েছে যে কলব্যাক পদ্ধতির কাজ হয় না (এমনকি পূর্ববর্তী মক সংস্করণে চেষ্টা করা হয়েছে)। আপনার পরীক্ষার উপর নির্ভর করে আরেকটি সম্ভাব্য পন্থা হ'ল কেবল Setup()আবার কল করা, এবং Return()একটি আলাদা মান।
কেন্ট বুগার্ট


4

কিছুটা ভিন্ন প্রয়োজনের সাথে একই ধরণের সমস্যার জন্য এখানে পৌঁছেছি।
আমাকে বিভিন্ন ইনপুট মানগুলিতে ভিত্তি করে মোক থেকে বিভিন্ন রিটার্নের মানগুলি পাওয়া দরকার এবং এটির সমাধান খুঁজে পেল যা আইএমও আরও পাঠযোগ্য, এটি মোকের ডিক্যারেটিভ সিনট্যাক্স (লিনক টু মকস) ব্যবহার করে।

public interface IDataAccess
{
   DbValue GetFromDb(int accountId);  
}

var dataAccessMock = Mock.Of<IDataAccess>
(da => da.GetFromDb(It.Is<int>(acctId => acctId == 0)) == new Account { AccountStatus = AccountStatus.None }
&& da.GetFromDb(It.Is<int>(acctId => acctId == 1)) == new DbValue { AccountStatus = AccountStatus.InActive }
&& da.GetFromDb(It.Is<int>(acctId => acctId == 2)) == new DbValue { AccountStatus = AccountStatus.Deleted });

var result1 = dataAccessMock.GetFromDb(0); // returns DbValue of "None" AccountStatus
var result2 = dataAccessMock.GetFromDb(1); // returns DbValue of "InActive"   AccountStatus
var result3 = dataAccessMock.GetFromDb(2); // returns DbValue of "Deleted" AccountStatus

আমার জন্য (এখানে 2019 সালের Moq 4.13.0), এটি এমনকি সংক্ষিপ্ত da.GetFromDb(0) == new Account { ..None.. && da.GetFromDb(1) == new Account { InActive } && ..., কোনও- It.Isল্যাম্বদার প্রয়োজন নেই worked
ojdo

3

গৃহীত উত্তর , সেইসাথে SetupSequence উত্তর , হ্যান্ডলগুলি ধ্রুবক ফিরিয়ে আনে।

Returns()কিছু দরকারী ওভারলোড রয়েছে যেখানে আপনি উপহাস পদ্ধতিতে প্রেরিত পরামিতিগুলির উপর ভিত্তি করে কোনও মান ফিরিয়ে দিতে পারেন। গৃহীত উত্তরে প্রদত্ত সমাধানের ভিত্তিতে those ওভারলোডগুলির জন্য এখানে আরও একটি এক্সটেনশন পদ্ধতি রয়েছে।

public static class MoqExtensions
{
    public static IReturnsResult<TMock> ReturnsInOrder<TMock, TResult, T1>(this ISetup<TMock, TResult> setup, params Func<T1, TResult>[] valueFunctions)
        where TMock : class
    {
        var queue = new Queue<Func<T1, TResult>>(valueFunctions);
        return setup.Returns<T1>(arg => queue.Dequeue()(arg));
    }
}

দুর্ভাগ্যক্রমে, পদ্ধতিটি ব্যবহারের জন্য আপনাকে কয়েকটি টেম্পলেট প্যারামিটার নির্দিষ্ট করতে হবে, তবে ফলাফলটি এখনও বেশ পঠনযোগ্য।

repository
    .Setup(x => x.GetPageByUrl<IPageModel>(path))
    .ReturnsInOrder(new Func<string, IPageModel>[]
        {
            p => null, // Here, the return value can depend on the path parameter
            p => pageModel.Object,
        });

একাধিক পরামিতি (সহ এক্সটেনশন পদ্ধতির জন্য overloads তৈরি করুন T2, T3, ইত্যাদি) প্রয়োজন হলে।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.