Як я можу перевірити, як метод викликався точно один раз за допомогою Moq?


112

Як я можу перевірити, як метод викликався точно один раз за допомогою Moq? Річ Verify()проти Verifable()нас справді заплутана.

Відповіді:


165

Ви можете використовувати 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 - Вказує, що глузливий метод слід викликати рівно один раз.

Просто пам’ятайте, що це виклики методів; Я продовжував спрацьовувати, думаючи, що вони є властивостями, і забував дужки.


2
тож як отримати / налаштувати mockContext?
Чоко

2
@Choco Я припускаю, що це лише його екземпляр Mock. Тож це було щось на кшталт var mockContext = new Mock<IContext>()налаштування.
Зак Хубер

Я просто дивуюся , як AtLeast, AtMost, Betweenабо Exactlyможна було б розглядати як власність. Я маю на увазі, їм потрібен параметр, щоб зробити щось.
Данило Єлізаров

8

Уявіть, що ми будуємо калькулятор з одним методом додавання 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, що в цьому випадку підірветься, але це не так.
dudeNumber4

@ dudeNumber4 Ні, це не підірветься, тому що за замовчуванням Moq заглушить усі властивості та методи, як тільки ви створите Mockоб’єкт. Тож навіть без виклику Setup, Moq вже переробив методи для того, IPrinterщоб ви могли просто зателефонувати Verify. Однак, як хороша практика, я завжди налаштовую це, тому що нам може знадобитися примусово встановити параметри методу або повернути значення методу.
CodingYoshi

Вибачте, це було жахливе пояснення. Я зателефонував, Times.Exactly(1)і він не провалився, коли метод насправді викликався двічі. Лише після додавання Setupдо відповідного методу він вийшов з ладу неправильно.
dudeNumber4

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);
    }

І коли метод 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));
    }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.