سؤال

هل من الممكن تعيين out/ref المعلمة باستخدام موك (3.0+)?

لقد بحثت في استخدام Callback(), ولكن Action<> لا يدعم المرجع المعلمات لأنه يقوم على الوراثة.أود أيضا ويفضل أن يكون مثل وضع القيد (It.Is) على المدخلات ref المعلمة ، على الرغم من أنني يمكن أن تفعل ذلك في رد.

وأنا أعلم أن وحيد القرن يسخر يدعم هذه الوظيفة ، ولكن مشروع أعمل عليه هو بالفعل باستخدام موك.

هل كانت مفيدة؟

المحلول

وعلى الرغم من أن السؤال هو حول موك 3 (ربما يرجع إلى عصرها)، اسمحوا لي أن مرحلة ما بعد حل لموك 4.8، التي لديها الكثير من الدعم لتحسين كل المرجع المعلمات.

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

وبالمناسبة: يعمل It.Ref<T>.IsAny أيضا لC # 7 المعلمات in (لأنها أيضا من قبل المرجع)

نصائح أخرى

ل'خارج'، يبدو التالية للعمل بالنسبة لي.

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

وأنا على التخمين بأن موك ينظر إلى قيمة 'expectedValue "عند استدعاء الإعداد ويتذكر ذلك.

لref، وأنا أبحث عن إجابة أيضا.

ولقد وجدت دليل التشغيل السريع التالية مفيدة: https://github.com/Moq/moq4/wiki/Quickstart

تحرير:في موك 4.10, يمكنك الآن تمر مندوب له أو المرجع المعلمة مباشرة إلى وظيفة رد الاتصال:

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

سيكون لديك لتحديد مندوب ومثيل ذلك:

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

موك النسخة قبل 4.10:

أفنير كاشتان يوفر طريقة التمديد في مدونته التي تتيح إعداد المعلمة من رد: موك ، الاسترجاعات والخروج المعلمات:خاصة صعبة حالة الحافة

الحل على حد سواء أنيق و hacky.أنيقة في أنه يوفر بطلاقة الجملة التي يشعر في المنزل مع موك رد.و hacky لأنه يعتمد على استدعاء بعض الداخلي موك واجهات برمجة التطبيقات عن طريق التفكير.

طريقة التمديد المقدمة في الرابط أعلاه لم يجمع بالنسبة لي, حتى لقد قدمت نسخة معدلة أدناه.سوف تحتاج إلى إنشاء توقيع لكل عدد من معلمات الإدخال لديك ؛ لقد قدمت 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);
}

..التالية موك الإعداد:

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

وهذا هو وثائق من موك الموقع :

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

ويبدو أنه من غير الممكن من خارج منطقة الجزاء. تبدو كمن يحاول حل

وانظر هذا المنتدى آخر http://code.google.com/p/moq/issues/ التفاصيل؟ ID = 176

وهذا السؤال تحقق قيمة المعلمة إشارة مع موك

لإرجاع قيمة مع وضع المعلمة المرجع هنا هو قطعة من التعليمات البرمجية:

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

ويمكن أن يكون هذا الحل.

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

}

وأنا ناضلت مع العديد من الاقتراحات هنا قبل I بسيط إنشاء مثيل من فئة جديدة "وهمية" التي تطبق أيا كان واجهة تحاول موك بها. بعد ذلك يمكنك ببساطة وضع قيمة المعلمة خارج مع أسلوب نفسها.

وأنا ناضلت مع هذا لمدة ساعة بعد ظهر هذا اليوم، ولا يمكن العثور على إجابة في أي مكان. بعد ان لعب في جميع أنحاء لوحدي معها وكنت قادرا على التوصل إلى الحل الذي عملت بالنسبة لي.

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 ثم هذا سوف تعمل بشكل جيد.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top