Atribuindo / ref parâmetros em Moq

É possível atribuir um parâmetro out / ref usando Moq (3.0+)?

Eu olhei usando Callback() , mas Action não suporta parâmetros ref porque é baseado em genéricos. Eu também preferiria colocar uma restrição ( It.Is ) na input do parâmetro ref , embora eu possa fazer isso no retorno de chamada.

Eu sei que o Rhino Mocks suporta essa funcionalidade, mas o projeto em que estou trabalhando já está usando o Moq.

Enquanto a questão é sobre o Moq 3 (provavelmente devido à sua idade), permita-me postar uma solução para o Moq 4.8, que tem muito melhor suporte para os parâmetros by-ref.

 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(); mock.Setup(m => m.Gobble(ref It.Ref.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); } 

By the way: It.Ref.IsAny também funciona para C # 7 in parâmetros (desde que eles também são by-ref).

Para ‘out’, o seguinte parece funcionar para mim.

 public interface IService { void DoSomething(out string a); } [TestMethod] public void Test() { var service = new Mock(); var expectedValue = "value"; service.Setup(s => s.DoSomething(out expectedValue)); string actualValue; service.Object.DoSomething(out actualValue); Assert.AreEqual(actualValue, expectedValue); } 

Eu estou supondo que Moq olha para o valor de ‘expectedValue’ quando você chama Setup e se lembra dele.

Para ref , estou procurando uma resposta também.

Eu encontrei o seguinte guia QuickStart útil: https://github.com/Moq/moq4/wiki/Quickstart

O Avner Kashtan fornece um método de extensão em seu blog que permite configurar o parâmetro de saída a partir de um retorno de chamada: parâmetros Moq, Callbacks e Out: um caso de borda particularmente difícil

A solução é elegante e hacky. Elegante na medida em que fornece uma syntax fluente que se sente em casa com outras chamadas de retorno do Moq. E hacky porque depende de chamar algumas APIs Moq internas por meio de reflection.

O método de extensão fornecido no link acima não compilou para mim, então eu forneci uma versão editada abaixo. Você precisará criar uma assinatura para cada número de parâmetros de input que você possui; Eu forneci 0 e 1, mas estendê-lo ainda mais deve ser simples:

 public static class MoqExtensions { public delegate void OutAction(out TOut outVal); public delegate void OutAction(T1 arg1, out TOut outVal); public static IReturnsThrows OutCallback(this ICallback mock, OutAction action) where TMock : class { return OutCallbackInternal(mock, action); } public static IReturnsThrows OutCallback(this ICallback mock, OutAction action) where TMock : class { return OutCallbackInternal(mock, action); } private static IReturnsThrows OutCallbackInternal(ICallback 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; } } 

Com o método de extensão acima, você pode testar uma interface com parâmetros como:

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

.. com a seguinte configuração do Moq:

  [TestMethod] public void ParserTest() { Mock parserMock = new Mock(); 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 : Para suportar os methods de retorno de void, você simplesmente precisa adicionar novos methods de sobrecarga:

 public static ICallbackResult OutCallback(this ICallback mock, OutAction action) { return OutCallbackInternal(mock, action); } public static ICallbackResult OutCallback(this ICallback mock, OutAction 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; } 

Isso permite testar interfaces como:

 public interface IValidationRule { void Validate(string input, out string message); } [TestMethod] public void ValidatorTest() { Mock validatorMock = new Mock(); 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); } 

Esta é a documentação do site do Moq :

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

Parece que não é possível fora da checkbox. Parece que alguém tentou uma solução

Veja este post no fórum http://code.google.com/p/moq/issues/detail?id=176

esta pergunta Verifique o valor do parâmetro de referência com o Moq

Isso pode ser uma solução.

 [Test] public void TestForOutParameterInMoq() { //Arrange _mockParameterManager= new Mock(); Mock mockParameter= new Mock(); //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()); } 

Para retornar um valor junto com a configuração do parâmetro ref, aqui está um trecho de código:

 public static class MoqExtensions { public static IReturnsResult DelegateReturns(this IReturnsThrows 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)mock; } } 

Em seguida, declare seu próprio delegado correspondente à assinatura do método a ser ridicularizado e forneça sua própria implementação de método.

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

Eu lutei com isso por uma hora esta tarde e não consegui encontrar uma resposta em nenhum lugar. Depois de brincar sozinho, consegui encontrar uma solução que funcionasse para mim.

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

A chave aqui é mock.SetupAllProperties(); que irá eliminar todas as propriedades para você. Isso pode não funcionar em todos os cenários de teste, mas se tudo o que importa é obter o return value de return value de YourMethod então isso funcionará bem.