Pregunta ¿Me puede ayudar a entender la devolución de llamada Moq?


Usando Moq y mirando Callback pero no he podido encontrar un ejemplo simple para entender cómo usarlo.

¿Tiene un pequeño fragmento de trabajo que explica claramente cómo y cuándo usarlo?


76
2018-05-14 09:44


origen


Respuestas:


Difícil de superar https://github.com/Moq/moq4/wiki/Quickstart

Si eso no es lo suficientemente claro, lo llamaría un error de doc ...

EDITAR: En respuesta a tu aclaración ...

Para cada método burlado Setup usted realiza, puede indicar cosas como:

  • restricciones en las entradas
  • el valor para / forma en que se deriva el valor de retorno (si hay uno)

los .Callback mecanismo dice "No puedo describirlo ahora, pero cuando ocurre una llamada como esta, llámame y haré lo que sea necesario". Como parte de la misma cadena de llamadas fluidas, puede controlar el resultado para regresar (si corresponde) a través de .Returns". En los ejemplos de QS, un ejemplo es que hacen que el valor que se devuelve aumente cada vez.

En general, no necesitará un mecanismo como este muy a menudo (los Patrones de Prueba xUnit tienen términos para antipatterns de las pruebas de Lógicas Condicionales de la clase), y si hay alguna manera más simple o incorporada de establecer lo que necesita, debe ser usado en preferencia

Parte 3 de 4 en la serie Moq de Justin Etheredge lo cubre, y hay otro ejemplo de devoluciones de llamada aquí


65
2018-05-14 14:06



Aquí hay un ejemplo de uso de una devolución de llamada para probar una entidad enviada a un servicio de datos que maneja una inserción.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

Sintaxis alternativa del método genérico:

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

Entonces puedes probar algo como

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");

46
2018-01-30 21:21



Hay dos tipos de Callback en moq. Uno sucede antes de que regrese la llamada; el otro sucede después de que la llamada vuelve.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

En ambas devoluciones de llamada, podemos:

  1. inspeccionar los argumentos del método
  2. método de captura arguemnts
  3. cambiar el estado contextual

6
2018-01-26 01:10



Callback es simplemente un medio para ejecutar cualquier código personalizado que desee cuando se realiza una llamada a uno de los métodos de prueba. Aquí hay un ejemplo simple:

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

Recientemente me encontré con un caso de uso interesante. Supongamos que espera algunas llamadas a su simulacro, pero suceden al mismo tiempo. Por lo tanto, no tiene forma de saber el orden en el que los llamarán, pero desea saber si las llamadas que esperaba tuvieron lugar (independientemente de la orden). Puedes hacer algo como esto:

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

Por cierto, no te confundas con el engañoso "antes Returns" y después Returns"distinción. Es simplemente una distinción técnica de si su código personalizado se ejecutará después Returns ha sido evaluado o antes. A los ojos de quien llama, ambos se ejecutarán antes de que se devuelva el valor. De hecho, si el método es void-revocando que ni siquiera puedes llamar Returns y sin embargo, funciona igual. Para más información, ver https://stackoverflow.com/a/28727099/67824.


2
2017-08-10 11:10



Además de las otras buenas respuestas aquí, lo he usado para realizar la lógica antes de lanzar una excepción. Por ejemplo, necesitaba almacenar todos los objetos que se pasaron a un método para su posterior verificación, y ese método (en algunos casos de prueba) necesitó arrojar una excepción. Vocación .Throws(...)en Mock.Setup(...) anula el Callback() acción y nunca lo llama. Sin embargo, al lanzar una excepción dentro de la Devolución de llamada, aún puede hacer todas las cosas buenas que una devolución de llamada tiene para ofrecer, y aun lanzar una excepción.


1
2018-01-10 03:03