¿Cómo puedo verificar que un método fue llamado exactamente una vez con Moq?


¿Cómo puedo verificar que un método fue llamado exactamente una vez con Moq? Lo de Verify() vs. Verifable() es realmente confuso.

Author: Roman Marusyk, 2010-11-17

3 answers

Puedes usar Times.Once(), o Times.Exactly(1):

mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));

Aquí están los métodos de la clase Times :

  • AtLeast - Especifica que un método burlado debe ser invocado veces veces como mínimo.
  • AtLeastOnce - Especifica que un método burlado debe ser invocado una vez como mínimo.
  • AtMost - Especifica que un método burlado debe ser invocado veces tiempo como máximo.
  • AtMostOnce - Especifica que un método burlado debe ser invocado una vez como máximo.
  • Between - Especifica que un método burlado debe ser invocado entre from y to times.
  • Exactly - Especifica que un método burlado debe ser invocado exactamente veces veces.
  • Never - Especifica que un método burlado no debe ser invocado.
  • Once - Especifica que un método burlado debe ser invocado exactamente una vez.

Solo recuerde que son llamadas de método; seguí tropezando, pensando que eran propiedades y olvidando la paréntesis.

 128
Author: Jeff Ogata,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-12-12 12:46:13

Imagine que tenemos están construyendo una calculadora con un método para agregar 2 enteros. Imaginemos además que el requisito es que cuando se llama al método add, llama al método print una vez. Así es como probaríamos esto:

public interface IPrinter
{
    void Print(int answer);
}

public class ConsolePrinter : IPrinter
{
    public void Print(int answer)
    {
        Console.WriteLine("The answer is {0}.", answer);
    }
}

public class Calculator
{
    private IPrinter printer;
    public Calculator(IPrinter printer)
    {
        this.printer = printer;
    }

    public void Add(int num1, int num2)
    {
        printer.Print(num1 + num2);
    }
}

Y aquí está la prueba real con comentarios dentro del código para mayor aclaración:

[TestClass]
public class CalculatorTests
{
    [TestMethod]
    public void WhenAddIsCalled__ItShouldCallPrint()
    {
        /* Arrange */
        var iPrinterMock = new Mock<IPrinter>();

        // Let's mock the method so when it is called, we handle it
        iPrinterMock.Setup(x => x.Print(It.IsAny<int>()));

        // Create the calculator and pass the mocked printer to it
        var calculator = new Calculator(iPrinterMock.Object);

        /* Act */
        calculator.Add(1, 1);

        /* Assert */
        // Let's make sure that the calculator's Add method called printer.Print. Here we are making sure it is called once but this is optional
        iPrinterMock.Verify(x => x.Print(It.IsAny<int>()), Times.Once);

        // Or we can be more specific and ensure that Print was called with the correct parameter.
        iPrinterMock.Verify(x => x.Print(3), Times.Once);
    }
}
 3
Author: CodingYoshi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-09 19:41:36

El controlador de prueba puede ser:

  public HttpResponseMessage DeleteCars(HttpRequestMessage request, int id)
    {
        Car item = _service.Get(id);
        if (item == null)
        {
            return request.CreateResponse(HttpStatusCode.NotFound);
        }

        _service.Remove(id);
        return request.CreateResponse(HttpStatusCode.OK);
    }

Y Cuando se llama al método DeleteCars con id válido, entonces podemos verificar que, el método Service remove se llama exactamente una vez por esta prueba:

 [TestMethod]
    public void Delete_WhenInvokedWithValidId_ShouldBeCalledRevomeOnce()
    {
        //arange
        const int carid = 10;
        var car = new Car() { Id = carid, Year = 2001, Model = "TTT", Make = "CAR 1", Price=2000 };
        mockCarService.Setup(x => x.Get(It.IsAny<int>())).Returns(car);

        var httpRequestMessage = new HttpRequestMessage();
        httpRequestMessage.Properties[HttpPropertyKeys.HttpConfigurationKey] = new HttpConfiguration();

        //act
        var result = carController.DeleteCar(httpRequestMessage, vechileId);

        //assert
        mockCarService.Verify(x => x.Remove(carid), Times.Exactly(1));
    }
 1
Author: sanjeev bhusal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-14 20:59:25