Asignación de parámetros de salida / ref en Moq

¿Es posible asignar un parámetro out / ref usando Moq (3.0+)?

He analizado el uso de Callback() , pero Action no admite los parámetros de ref porque está basado en generics. También preferiría poner una restricción ( It.Is ) en la entrada del parámetro ref , aunque puedo hacerlo en la callback.

Sé que Rhino Mocks admite esta funcionalidad, pero el proyecto en el que estoy trabajando ya está usando Moq.

Si bien la pregunta es sobre Moq 3 (probablemente debido a su edad), permítanme publicar una solución para Moq 4.8, que tiene un soporte mucho mejor para los parámetros de 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); } 

Por cierto: It.Ref.IsAny también funciona para C # 7 in parámetros (ya que también son por ref).

Para ‘salir’, lo siguiente parece funcionar para mí.

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

Supongo que Moq mira el valor de ‘expectedValue’ cuando llamas al progtwig de instalación y lo recuerda.

Para ref , estoy buscando una respuesta también.

Encontré útil la siguiente guía QuickStart: https://github.com/Moq/moq4/wiki/Quickstart

Avner Kashtan proporciona un método de extensión en su blog que permite configurar el parámetro de salida de una callback: Parámetros Moq, Callbacks y Out: un caso particularmente complicado

La solución es elegante y hacky. Elegante ya que proporciona una syntax fluida que se siente en casa con otras devoluciones de llamada Moq. Y hacky porque se basa en llamar a algunas API Moq internas a través de la reflexión.

El método de extensión provisto en el enlace anterior no compiló para mí, así que proporcioné una versión editada a continuación. Tendrá que crear una firma para cada número de parámetros de entrada que tenga; Proporcioné 0 y 1, pero ampliarlo más debería ser simple:

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

Con el método de extensión anterior, puede probar una interfaz sin parámetros tales como:

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

.. con la siguiente configuración de 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); } 

Editar : para admitir métodos de retorno de vacío, solo necesita agregar nuevos métodos 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; } 

Esto permite probar interfaces tales 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 es la documentación del sitio 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 no es posible de la caja. Parece que alguien intentó una solución

Ver esta publicación en el foro http://code.google.com/p/moq/issues/detail?id=176

esta pregunta Verificar el valor del parámetro de referencia con Moq

Esto puede ser una solución.

 [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 devolver un valor junto con la configuración del parámetro ref, aquí hay un fragmento 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; } } 

Luego, declare a su propio delegado que coincida con la firma del método que se debe burlar y proporcione su propia implementación del 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; })); } 

Luché con esto por una hora esta tarde y no pude encontrar una respuesta en ningún lado. Después de jugar solo con eso, pude encontrar una solución que funcionó para mí.

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

La clave aquí es mock.SetupAllProperties(); que eliminará todas las propiedades por ti. Es posible que esto no funcione en todos los casos de prueba, pero si todo lo que le importa es obtener el return value de return value de YourMethod , esto funcionará bien.