মোকে / রেফ প্যারামিটার নির্ধারণ করা


293

Moq (3.0+) ব্যবহার করে একটি out/ refপরামিতি নির্ধারণ করা সম্ভব ?

আমি ব্যবহার দেখেছি Callback(), কিন্তু Action<>রেফ প্যারামিটারগুলি সমর্থন করি না কারণ এটি জেনেরিকের উপর ভিত্তি করে। আমি পরামিতিগুলির ইনপুটটিতে একটি বাধা ( It.Is) রাখতে পছন্দ refকরি, যদিও আমি কলব্যাকটিতে এটি করতে পারি।

আমি জানি যে রাইনো মকস এই কার্যকারিতাটি সমর্থন করে তবে আমি যে প্রকল্পে কাজ করছি তা ইতিমধ্যে মোক ব্যবহার করছে।


4
এই Q & A- সম্পর্কে MOQ 3. MOQ 4.8, বাই-সুত্র পরামিতি জন্য অনেক উন্নত সমর্থন আছে একটি ছোটো থেকে হয় It.IsAny<T>()-একটি মিলকারীর ( ref It.Ref<T>.IsAnyস্থাপনের জন্য সমর্থন করার জন্য) .Callback()এবং .Returns()পদ্ধতি স্বাক্ষর মিলে একটি কাস্টম প্রতিনিধি ধরনের মাধ্যমে। সুরক্ষিত পদ্ধতিগুলি সমানভাবে সমর্থিত। যেমন নীচে আমার উত্তর দেখুন
স্টাকেক্স

আপনি এটি ব্যবহার করতে পারবেন। উদাহরণস্বরূপ: moq.Setup (x => x.Method (এটি আউট। রেফ <স্ট্রিং>। কোনও)) .আরচনা (টিভিয়াল);
মিকবিটিসি

উত্তর:


116

মোখ সংস্করণ ৪.৮ (বা তারপরে) বাই-রেফারির পরামিতিগুলির জন্য অনেক উন্নত সমর্থন করেছে:

public interface IGobbler
{
    bool Gobble(ref int amount);
}

delegate void GobbleCallback(ref int amount);     // needed for Callback
delegate bool GobbleReturns(ref int amount);      // needed for Returns

var mock = new Mock<IGobbler>();
mock.Setup(m => m.Gobble(ref It.Ref<int>.IsAny))  // match any value passed by-ref
    .Callback(new GobbleCallback((ref int amount) =>
     {
         if (amount > 0)
         {
             Console.WriteLine("Gobbling...");
             amount -= 1;
         }
     }))
    .Returns(new GobbleReturns((ref int amount) => amount > 0));

int a = 5;
bool gobbleSomeMore = true;
while (gobbleSomeMore)
{
    gobbleSomeMore = mock.Object.Gobble(ref a);
}

একই প্যাটার্নটি outপরামিতিগুলির জন্য কাজ করে ।

It.Ref<T>.IsAnyসি # 7 inপরামিতিগুলির জন্যও কাজ করে (যেহেতু তারাও বাই-রেফ হয়)।


2
এটি সমাধান, এটি আপনাকে রেফ হিসাবে কোনও ইনপুট দেয়, ঠিক যেমন এটি অ রেফ ইনপুট জন্য কাজ করবে। এটি সত্যই একটি খুব উন্নত সমর্থন
ক্রেতাদ

5
এই একই সমাধান outযদিও জন্য কাজ করে না , তাই না?
এটিডি

1
@ATD আংশিক হ্যাঁ আউট প্যারামিটার সহ একটি প্রতিনিধি ঘোষণা করুন এবং উপরের সিনট্যাক্সের সাথে কলব্যাকের মধ্যে মান নির্ধারণ করুন
রয়েলটি

উল্লেখ করার মতো বিষয় যে আপনি যে ক্রিয়াকলাপটি উপহাস করছেন তার মধ্যে যদি আরও যুক্তি থাকে তবে কলব্যাক স্বাক্ষরের একই প্যাটার্নটি অনুসরণ করা উচিত (কেবলমাত্র রেফ / আউট প্যারামিটার নয়)
ইয়োয়াভ ফিউয়ারস্টেইন

320

'আউট' এর জন্য, নিম্নলিখিতগুলি আমার পক্ষে কাজ করে বলে মনে হচ্ছে।

public interface IService
{
    void DoSomething(out string a);
}

[TestMethod]
public void Test()
{
    var service = new Mock<IService>();
    var expectedValue = "value";
    service.Setup(s => s.DoSomething(out expectedValue));

    string actualValue;
    service.Object.DoSomething(out actualValue);
    Assert.AreEqual(expectedValue, actualValue);
}

আমি অনুমান করছি যে আপনি যখন সেটআপটিকে কল করেন এবং এটির স্মরণ রাখেন তখন মোক 'প্রত্যাশিত ভ্যালু'র মান দেখে।

কারণ ref, আমি একটি উত্তরও খুঁজছি।

আমি নিম্নলিখিত কুইকস্টার্ট গাইডকে দরকারী বলে মনে করেছি: https://github.com/Moq/moq4/wiki/Quickstart


7
আমার মনে হয় আমার যে সমস্যাটি হয়েছিল তা হ'ল পদ্ধতি থেকে আউট / রেফ প্যারামগুলি নির্ধারণের কোনও পদ্ধতি নেইSetup
রিচার্ড স্যাযালা

1
রেফ প্যারামিটার নির্ধারণের জন্য আমার কাছে কোনও সমাধান নেই। এই উদাহরণটি "বি" তে "আউটপুট মান" এর একটি মান নির্ধারণ করে। মেক আপনি সেটআপটিতে যে এক্সপ্রেশনটি পাস করেছেন তা কার্যকর করে না, এটি এটি বিশ্লেষণ করে বুঝতে পারে যে আপনি আউটপুট মানের জন্য 'ক' সরবরাহ করছেন, সুতরাং এটি 'এ' এর বর্তমান মানটি দেখে এবং পরবর্তী কলগুলির জন্য এটি মনে রাখে।
ক্রেগ Celeste

আউট ও রেফ উদাহরণগুলি এ দেখুন: কোড. google.com/p/moq/wiki/QuickStart
ট্রুওইল

9
যখন মক্কড ইন্টারফেস পদ্ধতিটি একটি আলাদা স্কোপে যার নিজস্ব রেফারেন্সড আউটপুট ভেরিয়েবল (যেমন অন্য শ্রেণীর পদ্ধতির অভ্যন্তরে। মক সেটআপ, তবে সমস্ত পরিস্থিতি সমাধান করা খুব সহজ। আউট / রেফ মানটি সুস্পষ্ট হ্যান্ডলিংয়ের জন্য সমর্থন moq এ দুর্বল (যেমন অন্য কেউ বলেছিলেন, মৃত্যুদন্ড কার্যকর হওয়ার সময় পরিচালিত হয়েছে)।
জন কে

2
+1: এটি একটি সহায়ক উত্তর। তবে: যদি আউট প্যারামিটার ধরণটি ক্লাস হয় তবে স্ট্রিংয়ের মতো বিল্ট-ইন টাইপ - আমি বিশ্বাস করি না এটি কাজ করবে। আজ চেষ্টা করলাম। মক অবজেক্ট কল সিমুলেট করে এবং "আউট" প্যারামিটারের মাধ্যমে একটি নাল ফেরায়।
আজহেগ্লোভ

86

সম্পাদনা করুন : মোখ ৪.১০ তে আপনি এখন একটি ডেলিগেট পাস করতে পারেন যার কলব্যাক ফাংশনে সরাসরি আউট বা রেফ প্যারামিটার রয়েছে:

mock
  .Setup(x=>x.Method(out d))
  .Callback(myDelegate)
  .Returns(...); 

আপনাকে একটি প্রতিনিধি নির্ধারণ করতে হবে এবং তা ইনস্ট্যান্ট করতে হবে:

...
.Callback(new MyDelegate((out decimal v)=>v=12m))
...

মক সংস্করণের জন্য ৪.১০ এর আগে:

আভনার কাশতান তার ব্লগে একটি এক্সটেনশন পদ্ধতি সরবরাহ করে যা কলব্যাক থেকে আউট প্যারামিটার সেট করার অনুমতি দেয়: মক, কলব্যাকস এবং আউট প্যারামিটারগুলি: একটি বিশেষত কঠিন প্রান্তের কেস

সমাধান মার্জিত এবং হ্যাকি উভয়ই। মার্জিত এতে এটি একটি সাবলীল সিনট্যাক্স সরবরাহ করে যা ঘরে ঘরে অন্য মক কলব্যাকের সাথে অনুভব করে। এবং হ্যাকি কারণ এটি প্রতিবিম্বের মাধ্যমে কিছু অভ্যন্তরীণ মাক এপিআই কল করার উপর নির্ভর করে।

উপরের লিঙ্কটিতে প্রদত্ত এক্সটেনশন পদ্ধতিটি আমার জন্য সংকলন করেনি, তাই আমি নীচে সম্পাদিত সংস্করণ সরবরাহ করেছি। আপনার কাছে থাকা প্রতিটি ইনপুট প্যারামিটারের জন্য আপনাকে একটি স্বাক্ষর তৈরি করতে হবে; আমি 0 এবং 1 সরবরাহ করেছি তবে এটিকে আরও বাড়ানো সহজ হওয়া উচিত:

public static class MoqExtensions
{
    public delegate void OutAction<TOut>(out TOut outVal);
    public delegate void OutAction<in T1,TOut>(T1 arg1, out TOut outVal);

    public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, TOut>(this ICallback<TMock, TReturn> mock, OutAction<TOut> action)
        where TMock : class
    {
        return OutCallbackInternal(mock, action);
    }

    public static IReturnsThrows<TMock, TReturn> OutCallback<TMock, TReturn, T1, TOut>(this ICallback<TMock, TReturn> mock, OutAction<T1, TOut> action)
        where TMock : class
    {
        return OutCallbackInternal(mock, action);
    }

    private static IReturnsThrows<TMock, TReturn> OutCallbackInternal<TMock, TReturn>(ICallback<TMock, TReturn> mock, object action)
        where TMock : class
    {
        mock.GetType()
            .Assembly.GetType("Moq.MethodCall")
            .InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock,
                new[] { action });
        return mock as IReturnsThrows<TMock, TReturn>;
    }
}

উপরের এক্সটেনশন পদ্ধতিতে, আপনি আউট প্যারামিটারগুলির সাথে একটি ইন্টারফেস পরীক্ষা করতে পারেন যেমন:

public interface IParser
{
    bool TryParse(string token, out int value);
}

.. নিম্নলিখিত Moq সেটআপ সহ:

    [TestMethod]
    public void ParserTest()
    {
        Mock<IParser> parserMock = new Mock<IParser>();

        int outVal;
        parserMock
            .Setup(p => p.TryParse("6", out outVal))
            .OutCallback((string t, out int v) => v = 6)
            .Returns(true);

        int actualValue;
        bool ret = parserMock.Object.TryParse("6", out actualValue);

        Assert.IsTrue(ret);
        Assert.AreEqual(6, actualValue);
    }



সম্পাদনা করুন : অকার্যকর-রিটার্ন পদ্ধতিগুলি সমর্থন করতে, আপনাকে কেবল নতুন ওভারলোড পদ্ধতি যুক্ত করতে হবে:

public static ICallbackResult OutCallback<TOut>(this ICallback mock, OutAction<TOut> action)
{
    return OutCallbackInternal(mock, action);
}

public static ICallbackResult OutCallback<T1, TOut>(this ICallback mock, OutAction<T1, TOut> action)
{
    return OutCallbackInternal(mock, action);
}

private static ICallbackResult OutCallbackInternal(ICallback mock, object action)
{
    mock.GetType().Assembly.GetType("Moq.MethodCall")
        .InvokeMember("SetCallbackWithArguments", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock, new[] { action });
    return (ICallbackResult)mock;
}

এটি পরীক্ষামূলক ইন্টারফেসগুলি যেমন:

public interface IValidationRule
{
    void Validate(string input, out string message);
}

[TestMethod]
public void ValidatorTest()
{
    Mock<IValidationRule> validatorMock = new Mock<IValidationRule>();

    string outMessage;
    validatorMock
        .Setup(v => v.Validate("input", out outMessage))
        .OutCallback((string i, out string m) => m  = "success");

    string actualMessage;
    validatorMock.Object.Validate("input", out actualMessage);

    Assert.AreEqual("success", actualMessage);
}

5
@ উইলবার্ট, আমি আমার উত্তরটি শূন্য-ফেরত ফাংশনগুলির জন্য অতিরিক্ত ওভারলোড নিয়ে আপডেট করেছি।
স্কট ওয়েগনার

2
আমি আমাদের টেস্ট স্যুটে এই সমাধানটি ব্যবহার করছি এবং কাজ করে যাচ্ছি। তবে Moq 4.10 এ আপডেট করার পরে, এটি আর হয় না।
রিস্টোগড

2
দেখে মনে হচ্ছে এটি প্রতিশ্রুতিতে github.com/moq/moq4/commit/… ভাঙা হয়েছে । এখন এটি করার আরও ভাল উপায় আছে?
স্পার্কপ্লাগ

1
এমকিউ ৪-এ ফাইআই, মেথডক্যাল এখন সেটআপের সম্পত্তি, সুতরাং উপরের আউটক্যালব্যাক অভ্যন্তরীণ সাহসগুলি পরিবর্তিত হয়var methodCall = mock.GetType().GetProperty("Setup").GetValue(mock); mock.GetType().Assembly.GetType("Moq.MethodCall") .InvokeMember("SetCallbackResponse", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance, null, methodCall, new[] { action });
মাইক মেকটেনি

1
@ রিস্টোগড, এমকিউ ৪.১০-এর আপডেটের সাথে সাথে আপনি এখন ডেলিগেটকে পাস করতে পারেন যা সরাসরি কলব্যাক mock.Setup(x=>x.Method(out d)).Callback(myDelegate).Returns(...);...Callback(new MyDelegate((out decimal v)=>v=12m))...;
ফাংশনটিতে

48

এটি মোক সাইট থেকে ডকুমেন্টেশন :

// out arguments
var outString = "ack";
// TryParse will return true, and the out argument will return "ack", lazy evaluated
mock.Setup(foo => foo.TryParse("ping", out outString)).Returns(true);


// ref arguments
var instance = new Bar();
// Only matches if the ref argument to the invocation is the same instance
mock.Setup(foo => foo.Submit(ref instance)).Returns(true);

5
এটি মূলত পারচের উত্তরের মতোই এবং একই সীমাবদ্ধতা রয়েছে, এটি ইনপুটের উপর নির্ভর করে আউট মানকে পরিবর্তন করতে পারে না এবং রেফ প্যারামিটারগুলিতে প্রতিক্রিয়া জানাতে পারে না।
রিচার্ড জাজলে

@ রিচার্ড জাজালা, আপনি হয়ত পারেন তবে আপনার আলাদা "আউটস্ট্রিং" পরামিতিগুলির সাথে আলাদা আলাদা সেটআপ করা দরকার
সিলু

17

মনে হচ্ছে এটি বাক্সের বাইরে সম্ভব নয়। দেখে মনে হচ্ছে কেউ সমাধানের চেষ্টা করেছে

এই ফোরামটি পোস্টটি দেখুন http://code.google.com/p/moq/issues/detail?id=176

এই প্রশ্নটি মোক সাথে রেফারেন্স প্যারামিটার মান যাচাই করুন


নিশ্চিত করার জন্য ধন্যবাদ. আমি আমার অনুসন্ধানে এই দুটি লিঙ্কটি পেয়েছিলাম, কিন্তু লক্ষ্য করেছি যে মক এর একটি বৈশিষ্ট্যকে "সাপোর্টিং রেফ / আউট প্যারামিটার" হিসাবে তালিকাভুক্ত করেছে, তাই আমি নিশ্চিত হতে চেয়েছিলাম।
রিচার্ড জাযালে

3

রেফ প্যারামিটার সেট করার সাথে একটি মান ফেরত দিতে, এখানে কোডের একটি অংশ:

public static class MoqExtensions
{
    public static IReturnsResult<TMock> DelegateReturns<TMock, TReturn, T>(this IReturnsThrows<TMock, TReturn> mock, T func) where T : class
        where TMock : class
    {
        mock.GetType().Assembly.GetType("Moq.MethodCallReturn`2").MakeGenericType(typeof(TMock), typeof(TReturn))
            .InvokeMember("SetReturnDelegate", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, mock,
                new[] { func });
        return (IReturnsResult<TMock>)mock;
    }
}

তার পরে বিদ্রূপকারী পদ্ধতির স্বাক্ষরের সাথে মিলে আপনার নিজস্ব প্রতিনিধি ঘোষণা করুন এবং আপনার নিজস্ব পদ্ধতি বাস্তবায়ন সরবরাহ করুন।

public delegate int MyMethodDelegate(int x, ref int y);

    [TestMethod]
    public void TestSomething()
    {
        //Arrange
        var mock = new Mock<ISomeInterface>();
        var y = 0;
        mock.Setup(m => m.MyMethod(It.IsAny<int>(), ref y))
        .DelegateReturns((MyMethodDelegate)((int x, ref int y)=>
         {
            y = 1;
            return 2;
         }));
    }

আপনি যখন ভেরিয়েবলটি y হিসাবে পাস হতে চলেছেন তখন আপনার কি অ্যাক্সেস নেই? আমার একটি ফাংশন রয়েছে যা ডেওফিউকে দুটি রেফার আর্গুমেন্ট নেয়। আমার এই দু'টিকেই মক স্টাবের একটি নির্দিষ্ট দিনে সেট করতে হবে এবং তৃতীয় যুক্তিটি মক ডাটাবেস প্রসঙ্গ। কিন্তু ডেলিগেট পদ্ধতিটি কেবল বলা হচ্ছে না। দেখে মনে হচ্ছে মোকের কাছে স্থানীয় "y" আপনার "মাইমাথোড" ফাংশনটি পাস করার সাথে মিল রয়েছে। এটি কি আপনার উদাহরণের জন্য কাজ করে? ধন্যবাদ.
গ্রেগ ভেরেস

3

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

// Define a delegate with the params of the method that returns void.
delegate void methodDelegate(int x, out string output);

// Define a variable to store the return value.
bool returnValue;

// Mock the method: 
// Do all logic in .Callback and store the return value.
// Then return the return value in the .Returns
mockHighlighter.Setup(h => h.SomeMethod(It.IsAny<int>(), out It.Ref<int>.IsAny))
  .Callback(new methodDelegate((int x, out int output) =>
  {
    // do some logic to set the output and return value.
    output = ...
    returnValue = ...
  }))
  .Returns(() => returnValue);

2

আমি নিশ্চিত স্কট এর সমাধান এক পর্যায়ে কাজ করেছে,

তবে ব্যক্তিগত এপিসে উঁকি দেওয়ার জন্য প্রতিবিম্বটি ব্যবহার না করার জন্য এটি একটি ভাল যুক্তি। এটি এখন ভেঙে গেছে।

আমি একটি প্রতিনিধি ব্যবহার করে প্যারামিটার সেট করতে সক্ষম হয়েছি

      delegate void MockOutDelegate(string s, out int value);

    public void SomeMethod()
    {
        ....

         int value;
         myMock.Setup(x => x.TryDoSomething(It.IsAny<string>(), out value))
            .Callback(new MockOutDelegate((string s, out int output) => output = userId))
            .Returns(true);
    }

1

এটি একটি সমাধান হতে পারে।

[Test]
public void TestForOutParameterInMoq()
{
  //Arrange
  _mockParameterManager= new Mock<IParameterManager>();

  Mock<IParameter > mockParameter= new Mock<IParameter >();
  //Parameter affectation should be useless but is not. It's really used by Moq 
  IParameter parameter= mockParameter.Object;

  //Mock method used in UpperParameterManager
  _mockParameterManager.Setup(x => x.OutMethod(out parameter));

  //Act with the real instance
  _UpperParameterManager.UpperOutMethod(out parameter);

  //Assert that method used on the out parameter of inner out method are really called
  mockParameter.Verify(x => x.FunctionCalledInOutMethodAfterInnerOutMethod(),Times.Once());

}

1
এটি মূলত পারচের উত্তরের মতোই এবং একই সীমাবদ্ধতা রয়েছে, এটি ইনপুটের উপর নির্ভর করে আউট মানকে পরিবর্তন করতে পারে না এবং রেফ প্যারামিটারগুলিতে প্রতিক্রিয়া জানাতে পারে না।
রিচার্ড জাজলে

1

আমি এখানে নতুন 'ফেক' শ্রেণীর একটি উদাহরণ তৈরি করার আগে আমি এখানে অনেক পরামর্শ দিয়ে संघर्ष করেছি যা আপনি মক করার চেষ্টা করছেন তার ইন্টারফেস প্রয়োগ করে। তারপরে আপনি কেবল পদ্ধতিটির সাহায্যে আউট প্যারামিটারের মানটি সেট করতে পারেন।


0

আমি আজ বিকেলে এক ঘন্টা এর জন্য লড়াই করেছি এবং কোথাও কোনও উত্তর খুঁজে পাইনি। এটির সাথে আমার নিজের সাথে খোলার পরে আমি একটি সমাধান নিয়ে আসতে পেরেছিলাম যা আমার পক্ষে কাজ করে।

string firstOutParam = "first out parameter string";
string secondOutParam = 100;
mock.SetupAllProperties();
mock.Setup(m=>m.Method(out firstOutParam, out secondOutParam)).Returns(value);

এখানে মূল কীটি mock.SetupAllProperties();আপনার জন্য সমস্ত সম্পত্তি রেখে দেবে। এটি প্রতিটি পরীক্ষার ক্ষেত্রে দৃশ্যে কাজ নাও করতে পারে, তবে আপনার যত্ন নেওয়া সমস্ত যদি এটির মতো return valueহয়ে থাকে YourMethodতবে এটি ভাল কাজ করবে।

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