Frage

Ist es möglich, ein out / ref Parameter mit Moq (3.0 +)?

zuweisen

Ich habe bei Verwendung Callback() gesucht, aber Action<> nicht ref Parameter unterstützen, weil es auf Generika basiert. Ich würde auch gerne vorzugsweise eine Einschränkung setzen (It.Is) am Eingang des ref Parameters, obwohl ich, dass in dem Callback tun kann.

Ich weiß, dass Rhino Mocks diese Funktionalität unterstützt, aber das Projekt arbeite ich an ist bereits mit Moq.

War es hilfreich?

Lösung

Während die Frage nach ist Moq 3 (wahrscheinlich aufgrund seines Alters), lassen Sie mich für Moq 4.8 eine Lösung zu schreiben, die durch-ref Parameter wesentlich verbesserte Unterstützung hat.

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

Übrigens:. It.Ref<T>.IsAny funktioniert auch für C # 7 in Parameter (da sie auch durch-ref sind)

Andere Tipps

'out', die folgende scheint für mich zu arbeiten.

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

Ich vermute, dass Moq auf den Wert von ‚expectedValue‘ aussieht, wenn Sie das Setup aufrufen und merkt es.

Für ref, ich bin nach einer Antwort suchen auch.

Ich fand die folgende Kurzanleitung nützlich: https://github.com/Moq/moq4/wiki/Quickstart

Bearbeiten : In Moq 4.10 können Sie jetzt einen Delegierten übergeben, die einen oder ref-Parameter direkt an die Callback-Funktion hat:

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

Sie müssen einen Delegaten definieren und instanziiert es:

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

Für Moq Version vor 4.10:

Avner Kashtan bietet eine Erweiterungsmethode in seinem Blog, die die Out-Parameter von einem Rückruf ermöglicht Einstellung: Moq, Rückrufe und Out-Parameter: ein besonders heikel Rand Fall

Die Lösung ist elegant und Hacky. Elegant, dass sie eine fließend Syntax bietet, die mit anderen Moq Rückrufe zu Hause fühlt. Und Hacky weil es stützt sich auf einige interne Moq APIs über Reflektion aufrufen.

Die Extension-Methode bei der oben angegebenen Link nicht für mich zusammenstellen, also habe ich eine editierte Version weiter unten. Hier finden Sie eine Signatur für jede Anzahl von Eingabeparametern erstellen müssen Sie haben; Ich habe 0 zur Verfügung gestellt und 1, sondern erstrecken sollte es weiter sein, einfach:

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

Mit der obigen Erweiterung Methode können Sie eine Schnittstelle mit out-Parametern testen, wie:

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

.. mit folgenden Moq Setup:

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


Bearbeiten : void-Rückgabeverfahren zu unterstützen, müssen Sie einfach neue Überlastung Methoden hinzuzufügen:

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

Dies ermöglicht das Testen Schnittstellen wie:

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

Dies ist die Dokumentation von Moq Website :

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

Scheint, wie es nicht möglich, aus der Box ist. Sieht aus wie jemand eine Lösung

versucht

Sehen Sie in diesem Forum Beitrag http://code.google.com/p/moq/issues/ Detail? id = 176

Diese Frage Überprüfen Wert der Referenzparameter mit Moq

einen Wert zurückgeben zusammen mit ref Parametereinstellung, hier ist ein Stück Code:

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

Dann Ihre eigenen Delegierten erklären die Unterschrift zu-verspottet Methode Anpassung und Ihre eigene Methode Umsetzung.

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

Dies kann eine Lösung sein.

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

}

kämpfte ich mit vielen der Vorschläge hier, bevor ich einfach eine Instanz einer neuen ‚Fälschung‘ Klasse geschaffen, was Schnittstelle implementiert Sie zu verspotten versuchen. Dann können Sie einfach den Wert der Out-Parameter mit der Methode selbst.

ich damit zu kämpfen an diesem Nachmittag für eine Stunde und könnte eine Antwort nicht überall finden. Nach dem Spielen mit ihm auf meinem eigenen um konnte ich mit einer Lösung kommen, die für mich gearbeitet.

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

Der Schlüssel hier ist mock.SetupAllProperties();, die alle Eigenschaften für Dich Stub werden. Dies kann in jedem Testfall-Szenario nicht funktionieren, aber wenn alles kümmern Sie ist die return value von YourMethod bekommen, dann wird dies gut funktionieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top