回答:
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回だけ呼び出す必要があることを指定します。これらはメソッド呼び出しであることを覚えておいてください。私はつまづき続け、それらは特性であると思い、括弧を忘れました。
var mockContext = new Mock<IContext>()
をセットアップするようなものでした。
AtLeast
、AtMost
、Between
、またはExactly
プロパティとして見ることができます。つまり、彼らは何かをするためにパラメータが必要です。
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
にその場合爆発することを期待するでしょうが、そうではありませんでした。
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メソッドが有効な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));
}