Как проверить, что метод был вызван ровно один раз с помощью Moq? Verify()
Против Verifable()
вещь действительно заблуждение.
Как проверить, что метод был вызван ровно один раз с помощью Moq? Verify()
Против Verifable()
вещь действительно заблуждение.
Ответы:
Вы можете использовать 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
- Указывает, что фиктивный метод должен вызываться между от и до времени.Exactly
- Указывает, что фиктивный метод должен вызываться ровно раз.Never
- Указывает, что фиктивный метод не должен вызываться.Once
- Указывает, что фиктивный метод должен быть вызван ровно один раз.Просто помните, что это вызовы методов; Я все время сбивался с толку, думая, что это свойства, и забывая о скобках.
var mockContext = new Mock<IContext>()
чтобы это настроить.
AtLeast
, AtMost
, Between
или Exactly
можно было бы рассматривать как собственность. Я имею в виду, что им, очевидно, нужен параметр, чтобы что-то делать.
Представьте, что мы создаем калькулятор с одним методом сложения двух целых чисел. Давайте представим себе, что при вызове метода добавления он вызывает метод печати один раз. Вот как мы это протестируем:
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);
}
}
Примечание . По умолчанию Moq заглушит все свойства и методы, как только вы создадите объект Mock. Таким образом, даже без вызова Setup
Moq уже заглушил методы, IPrinter
поэтому вы можете просто позвонить Verify
. Однако в качестве хорошей практики я всегда настраиваю его, потому что нам может потребоваться принудительно применить параметры метода, чтобы удовлетворить определенные ожидания, или возвращаемое значение метода, чтобы удовлетворить определенные ожидания, или количество раз, когда он был вызван.
Verify
, Times.Once
но не звонил Setup
. Я, конечно, ожидал, Verify
что в этом случае взорвется, но этого не произошло.
Mock
объект. Таким образом, даже без вызова Setup
Moq уже заглушил методы, IPrinter
поэтому вы можете просто позвонить Verify
. Однако в качестве хорошей практики я всегда настраиваю его, потому что нам может потребоваться принудительно применить параметры к методу или возвращаемое значение из метода.
Times.Exactly(1)
и он не потерпел неудачу, когда метод фактически был вызван дважды. Только после добавления Setup
рассматриваемого метода произошла ошибка.
Контроллер тестирования может быть:
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);
}
И когда метод DeleteCars вызывается с действительным идентификатором, мы можем проверить это, метод удаления службы вызывается ровно один раз в этом тесте:
[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));
}