Як я можу перевірити, як метод викликався точно один раз за допомогою 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
можна було б розглядати як власність. Я маю на увазі, їм потрібен параметр, щоб зробити щось.
Уявіть, що ми будуємо калькулятор з одним методом додавання 2 цілих чисел. Давайте уявимо, що вимога полягає в тому, що коли викликається метод додавання, він викликає метод друку один раз. Ось як ми перевіримо це:
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));
}