如何使用Moq验证方法是否只调用一次? Verify()
与Verifable()
之间的关系非常混乱。
答案 0 :(得分:144)
您可以使用Times.Once()
或Times.Exactly(1)
:
mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));
以下是Times类的方法:
AtLeast
- 指定应该按次数调用模拟方法。AtLeastOnce
- 指定应该至少调用一次模拟方法。AtMost
- 指定应该按时间调用模拟方法作为最大值。AtMostOnce
- 指定应该最多调用一次模拟方法。Between
- 指定应在from和to之间调用模拟方法。Exactly
- 指定应该多次调用模拟方法。Never
- 指定不应调用模拟方法。Once
- 指定应该只调用一次模拟方法。请记住,他们是方法调用;我不断被绊倒,认为他们是属性而忘记了括号。
答案 1 :(得分:6)
想象一下,我们正在构建一个计算器,其中包含一种添加2个整数的方法。让我们进一步想象一下,当调用add方法时,它会调用print方法一次。以下是我们如何测试这个:
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);
}
}
以下是代码中包含注释的实际测试,以便进一步说明:
[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);
}
}
答案 2 :(得分:2)
测试控制器可能是:
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);
}
当使用有效id调用DeleteCars方法时,我们可以通过此测试验证,Service remove方法只调用一次:
[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));
}