メソッドがMoqで1回だけ呼び出されたことを確認するにはどうすればよいですか?


111

メソッドがMoqで1回だけ呼び出されたことを確認するにはどうすればよいですか?Verify()対のVerifable()事は本当に混乱しています。

回答:


164

Times.Once()またはを使用できますTimes.Exactly(1)

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

Timesクラスのメソッドは次のとおりです。

  • AtLeast -モックされたメソッドを最小回数回呼び出す必要があることを指定します。
  • AtLeastOnce -モックされたメソッドを最低1回呼び出す必要があることを指定します。
  • AtMost -モックされたメソッドを呼び出す回数を最大時間として指定します。
  • AtMostOnce -モックされたメソッドを最大で1回呼び出すことを指定します。
  • Between -モックされたメソッドがfromからtoまでの間に呼び出されることを指定します。
  • Exactly -モックされたメソッドを正確に何度も呼び出す必要があることを指定します。
  • Never -モックされたメソッドを呼び出さないことを指定します。
  • Once -モックされたメソッドを1回だけ呼び出す必要があることを指定します。

これらはメソッド呼び出しであることを覚えておいてください。私はつまづき続け、それらは特性であると思い、括弧を忘れました。


2
では、mockContextをどのように取得/セットアップしますか?
Choco

2
@Choco私はそれが彼のMockインスタンスだと思います。だから、それvar mockContext = new Mock<IContext>()をセットアップするようなものでした。
Zack Huber

私はどれだけだろうAtLeastAtMostBetween、またはExactlyプロパティとして見ることができます。つまり、彼らは何かをするためにパラメータが必要です。
Danylo Yelizarov

8

2つの整数を加算する1つの方法で電卓を作成しているとしましょう。さらに、addメソッドが呼び出されたときに、printメソッドを1回呼び出す必要があることを想像してみましょう。これをテストする方法は次のとおりです。

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

:デフォルトでは、Mockオブジェクトを作成するとすぐに、Moqはすべてのプロパティとメソッドをスタブします。したがって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メソッドが有効なIDで呼び出された場合、このテストによってService removeメソッドが1回だけ呼び出されたことを確認できます。

 [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));
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.