397 votes

Affectation/ref paramètres dans Moq

Est-il possible d'attribuer un/ref paramètre à l'aide de Moq (3.0)?

J'ai regardé l'aide d' Callback(), mais Action<> ne prend pas en charge les paramètres de ref, car il est basé sur les médicaments génériques. J'avais aussi, de préférence, comme pour mettre une contrainte (It.Is) à l'entrée de l' ref paramètre, si je peux le faire dans la fonction de rappel.

Je sais que le Rhino se moque prend en charge cette fonctionnalité, mais le projet sur lequel je travaille est d'ores et déjà à l'aide de Moq.

403voto

Parched Squid Points 3713

Pour les "out", la suite semble fonctionner pour moi.

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

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

    string b;
    service.Object.DoIt(out b);
    Assert.AreEqual("output value", b);
}

Je suppose qu'Moq regarde la valeur de 'a' lorsque vous appelez le programme d'Installation et se souvient-il.

Pour "ref", je suis à la recherche d'une réponse aussi.

J'ai trouvé ce guide de Démarrage rapide utile: http://code.google.com/p/moq/wiki/QuickStart

105voto

Scott Wegner Points 1773

Avner Kashtan fournit une méthode d'extension dans son blog qui permet de définir le paramètre de sortie à partir d'un rappel: Moq, les Rappels et les paramètres de Sortie: particulièrement délicate cas de bord

La solution est à la fois élégante et hacky. Élégant en ce qu'elle offre couramment de la syntaxe qui se sent à la maison avec d'autres Moq rappels. Et hacky parce qu'il repose sur l'appel à l'interne Moq Api via la réflexion.

La méthode d'extension fourni dans le lien ci-dessus ne compile pas pour moi, donc j'ai fourni une version éditée ci-dessous. Vous aurez besoin de créer une signature pour chaque nombre de paramètres d'entrée que vous avez; j'ai fourni des 0 et des 1, mais en l'étendant devrait en outre être simple:

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

Avec l'extension de la méthode, vous pouvez tester une interface avec les paramètres de sortie tels que:

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

.. avec les suivants Moq de l'installation:

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



Edit: À l'appui de void-retour des méthodes, vous avez simplement besoin d'ajouter de nouveaux surcharge de méthodes:

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

Ceci permet de tester des interfaces telles que:

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

58voto

Kosau Points 417

C'est la documentation de Moq site:

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

16voto

Gishu Points 59012

Me semble qu'il n'est pas possible de sortir de la boîte. On dirait que quelqu'un a tenté une solution

Voir ce post sur le forum http://code.google.com/p/moq/issues/detail?id=176

cette question http://stackoverflow.com/questions/726630/verify-value-of-reference-parameter-with-moq

0voto

Fabrice Points 1

Cela peut être une solution .

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

}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X