remarks generate example c# parameters moq ref out

c# - generate - Asignando parámetros/ref en Moq



params comments c# (9)

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

He analizado el uso de Callback() , pero Action<> no admite parámetros de referencia porque se basa en genéricos. También me gustaría, preferiblemente, poner una restricción ( It.Is ) en la entrada del parámetro ref , aunque puedo hacerlo en la devolución de llamada.

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


Avner Kashtan proporciona un método de extensión en su blog que permite configurar el parámetro out a partir de una devolución de llamada: Moq, Callbacks y Out parámetros: un caso de borde particularmente complicado

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

El método de extensión provisto en el enlace anterior no se compiló para mí, por lo que proporcioné una versión editada a continuación. Deberá crear una firma para cada número de parámetros de entrada que tenga; He proporcionado 0 y 1, pero extenderlo más debería ser 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>; } }

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



Edición : para admitir los métodos de devolución de vacíos, simplemente necesita agregar nuevos métodos de sobrecarga:

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

Esto permite probar interfaces como:

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


Esta es la documentación del code.google.com/p/moq/wiki/QuickStart :

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


Esto puede ser una solución.

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


Luché con esto durante una hora esta tarde y no pude encontrar una respuesta en ninguna parte. Después de jugar solo con él, 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(); el cual eliminará todas las propiedades para ti. Es posible que esto no funcione en todos los casos de prueba, pero si lo único que le importa es obtener el return value de return value de YourMethod entonces esto funcionará bien.


Luché con muchas de las sugerencias aquí antes de que simplemente creara una instancia de una nueva clase ''Fake'' que implementa cualquier interfaz que esté intentando simular. Luego, simplemente puede establecer el valor del parámetro out con el método en sí.


Para ''out'', lo siguiente parece funcionar para mí.

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(actualValue, expectedValue); }

Supongo que Moq mira el valor de ''expectedValue'' cuando llama a Configuración y lo recuerda.

Para ref , estoy buscando una respuesta también.

Encontré útil la siguiente guía de inicio rápido: https://github.com/Moq/moq4/wiki/Quickstart


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

Luego declare su propio delegado que coincida con la firma del método to-be-be-mocked 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<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; })); }



Si bien la pregunta es sobre Moq 3 (probablemente debido a su edad), permítame publicar una solución para Moq 4.8, que tiene un soporte mucho mayor para los parámetros de referencia.

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

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