¿Cómo verifico que se haya llamado a un método exactamente una vez con Moq? La cosa Verify()vs. Verifable()es realmente confusa.
¿Cómo verifico que se haya llamado a un método exactamente una vez con Moq? La cosa Verify()vs. Verifable()es realmente confusa.
Respuestas:
Puede usar Times.Once(), o Times.Exactly(1):
mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));
Estos son los métodos de la clase Times :
AtLeast - Especifica que un método simulado debe invocarse veces como mínimo.AtLeastOnce - Especifica que un método simulado debe invocarse una vez como mínimo.AtMost - Especifica que un método simulado debe invocarse por tiempo como máximo.AtMostOnce - Especifica que un método simulado debe invocarse una vez como máximo.Between - Especifica que se debe invocar un método simulado entre las horas desde y hasta.Exactly - Especifica que un método simulado debe invocarse exactamente las veces.Never - Especifica que no se debe invocar un método simulado.Once - Especifica que un método simulado debe invocarse exactamente una vez.Recuerde que son llamadas a métodos; Seguí tropezando, pensando que eran propiedades y olvidándome del paréntesis.
var mockContext = new Mock<IContext>()configurar eso.
AtLeast, AtMost, Between, o Exactlypodría ser visto como una propiedad. Quiero decir, obviamente necesitan un parámetro para hacer algo.
Imagina que estamos construyendo una calculadora con un método para sumar 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);
}
}
Nota : De forma predeterminada, Moq eliminará todas las propiedades y métodos tan pronto como cree un objeto Mock. Entonces, incluso sin llamar Setup, Moq ya ha eliminado los métodos para IPrinterque pueda llamar Verify. Sin embargo, como buena práctica, siempre lo configuro porque es posible que necesitemos hacer cumplir los parámetros del método para cumplir con ciertas expectativas, o el valor de retorno del método para cumplir con ciertas expectativas o la cantidad de veces que se ha llamado.
Verify, Times.Oncesin llamar nunca Setup. Ciertamente esperaría Verifyexplotar en ese caso, pero no fue así.
Mockobjeto. Entonces, incluso sin llamar Setup, Moq ya ha eliminado los métodos para IPrinterque pueda llamar Verify. Sin embargo, como buena práctica, siempre lo configuro porque es posible que necesitemos aplicar los parámetros al método o el valor de retorno del método.
Times.Exactly(1)y no falló cuando el método se llamó dos veces. Solo después de agregar Setupel método en cuestión, falló correctamente.
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 una identificación válida, entonces podemos verificar que, el método de eliminación del servicio 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));
}