.net 如何验证使用 Moq 只调用一次方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4206193/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 14:56:20  来源:igfitidea点击:

How do I verify a method was called exactly once with Moq?

.netmockingmoq

提问by Josh Kodroff

How do I verify a method was called exactly once with Moq? The Verify()vs. Verifable()thing is really confusing.

如何验证使用 Moq 只调用一次方法?在Verify()主场迎战Verifable()的是让人有些困惑。

回答by Jeff Ogata

You can use Times.Once(), or Times.Exactly(1):

您可以使用Times.Once(), 或Times.Exactly(1)

mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));

Here are the methods on the Timesclass:

以下是Times类的方法:

  • AtLeast- Specifies that a mocked method should be invoked times times as minimum.
  • AtLeastOnce- Specifies that a mocked method should be invoked one time as minimum.
  • AtMost- Specifies that a mocked method should be invoked times time as maximum.
  • AtMostOnce- Specifies that a mocked method should be invoked one time as maximum.
  • Between- Specifies that a mocked method should be invoked between from and to times.
  • Exactly- Specifies that a mocked method should be invoked exactly times times.
  • Never- Specifies that a mocked method should not be invoked.
  • Once- Specifies that a mocked method should be invoked exactly one time.
  • AtLeast- 指定应至少调用模拟方法的次数。
  • AtLeastOnce- 指定应至少调用一次模拟方法。
  • AtMost- 指定应调用模拟方法的时间为最大值。
  • AtMostOnce- 指定应最多调用一次模拟方法。
  • Between- 指定应在 from 和 to 之间调用模拟方法。
  • Exactly- 指定应准确调用模拟方法的次数。
  • Never- 指定不应调用模拟方法。
  • Once- 指定一个模拟方法应该被调用一次。

Just remember that they are method calls; I kept getting tripped up, thinking they were properties and forgetting the parentheses.

请记住,它们是方法调用;我一直被绊倒,认为它们是属性而忘记了括号。

回答by CodingYoshi

Imagine we are building a calculator with one method for adding 2 integers. Let's further imagine the requirement is that when the add method is called, it calls the print method once. Here is how we would test this:

想象一下,我们正在使用一种方法构建一个计算器,用于添加 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);
    }
}

And here is the actual test with comments within the code for further clarification:

以下是代码中带有注释的实际测试,以供进一步说明:

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

Note: By default Moq will stub all the properties and methods as soon as you create a Mock object. So even without calling Setup, Moq has already stubbed the methods for IPrinterso you can just call Verify. However, as a good practice, I always set it up because we may need to enforce the parameters to the method to meet certain expectations, or the return value from the method to meet certain expectations or the number of times it has been called.

注意:默认情况下,Moq 将在您创建 Mock 对象后立即存根所有属性和方法。因此,即使没有调用Setup,Moq 已经存根了 的方法,IPrinter因此您只需调用Verify. 然而,作为一个好的做法,我总是设置它,因为我们可能需要强制方法的参数满足某些期望,或者方法的返回值满足某些期望或调用次数。

回答by sanjeev bhusal

Test controller may be :

测试控制器可能是:

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

And When DeleteCars method called with valid id, then we can verify that, Service remove method called exactly once by this test :

当使用有效 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));
    }