Esta pregunta se puede resolver de variadas formas, sin embargo te mostramos la solución más completa para nosotros.
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(expectedValue, actualValue);
Supongo que Moq mira el valor de ‘valor esperado’ cuando llama al programa de instalación y lo recuerda.
Para ref
, Yo también estoy buscando una respuesta.
Encontré útil la siguiente guía de inicio rápido: https://github.com/Moq/moq4/wiki/Quickstart
La versión 4.8 de Moq (o posterior) tiene un soporte mucho mejor 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();
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);
El mismo patrón funciona para out
parámetros.
It.Ref
también funciona para C # 7 in
parámetros (ya que también son por referencia).
EDITAR: En Moq 4.10, ahora puede pasar un delegado que tiene un parámetro out o ref directamente a la función de devolución de llamada:
mock
.Setup(x=>x.Method(out d))
.Callback(myDelegate)
.Returns(...);
Tendrá que definir un delegado e instanciarlo:
...
.Callback(new MyDelegate((out decimal v)=>v=12m))
...
Para la versión de Moq anterior a la 4.10:
Avner Kashtan proporciona un método de extensión en su blog que permite establecer el parámetro de salida de una devolución de llamada: parámetros Moq, Callbacks y Out: un caso de borde particularmente complicado
La solución es elegante y hacky. Elegante porque proporciona una sintaxis fluida que se siente como en casa con otras devoluciones de llamada de 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 proporcionado 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(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
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 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: Apoyar void-retornar métodos, simplemente 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)
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 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);
Recuerda que tienes la opción de esclarecer tu experiencia si te ayudó.