Làm cách nào để xác minh một phương thức được gọi chính xác một lần với Moq? Điều Verify()
so với Verifable()
thực sự là khó hiểu.
Làm cách nào để xác minh một phương thức được gọi chính xác một lần với Moq? Điều Verify()
so với Verifable()
thực sự là khó hiểu.
Câu trả lời:
Bạn có thể sử dụng Times.Once()
, hoặc Times.Exactly(1)
:
mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));
Đây là các phương thức trên lớp Times :
AtLeast
- Chỉ định rằng một phương thức giả lập phải được gọi số lần là tối thiểu.AtLeastOnce
- Chỉ định rằng một phương thức giả lập nên được gọi một lần là tối thiểu.AtMost
- Chỉ định rằng một phương thức giả lập nên được gọi với thời gian tối đa.AtMostOnce
- Chỉ định rằng một phương thức giả lập nên được gọi tối đa một lần.Between
- Chỉ định rằng một phương thức chế nhạo nên được gọi từ và thường.Exactly
- Chỉ định rằng một phương thức giả lập nên được gọi chính xác lần.Never
- Chỉ định rằng không được gọi một phương thức giả mạo.Once
- Chỉ định rằng một phương thức giả lập phải được gọi chính xác một lần.Chỉ cần nhớ rằng chúng là các cuộc gọi phương thức; Tôi tiếp tục bị vấp ngã, nghĩ rằng chúng là tài sản và quên dấu ngoặc đơn.
var mockContext = new Mock<IContext>()
để thiết lập điều đó.
AtLeast
, AtMost
, Between
, hoặc Exactly
có thể được xem như tài sản. Ý tôi là, họ cần một tham số để làm điều gì đó.
Hãy tưởng tượng chúng ta đang xây dựng một máy tính với một phương pháp để cộng 2 số nguyên. Hãy hình dung thêm yêu cầu là khi phương thức add được gọi, nó sẽ gọi phương thức print một lần. Đây là cách chúng tôi sẽ kiểm tra điều này:
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);
}
}
Và đây là thử nghiệm thực tế với nhận xét trong mã để làm rõ thêm:
[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);
}
}
Lưu ý : Theo mặc định, Moq sẽ khai báo tất cả các thuộc tính và phương thức ngay khi bạn tạo một đối tượng Mock. Vì vậy, ngay cả khi không gọi Setup
, Moq đã cung cấp các phương thức IPrinter
để bạn có thể gọi Verify
. Tuy nhiên, như một phương pháp hay, tôi luôn thiết lập nó vì chúng ta có thể cần phải thực thi các tham số cho phương thức để đáp ứng những mong đợi nhất định hoặc giá trị trả về từ phương thức để đáp ứng những mong đợi nhất định hoặc số lần nó đã được gọi.
Verify
, Times.Once
mà không bao giờ gọi Setup
. Tôi chắc chắn sẽ Verify
nổ tung trong trường hợp đó, nhưng nó đã không.
Mock
đối tượng. Vì vậy, ngay cả khi không gọi Setup
, Moq đã cung cấp các phương thức IPrinter
để bạn có thể gọi Verify
. Tuy nhiên, như một thông lệ tốt, tôi luôn thiết lập nó vì chúng ta có thể cần phải thực thi các tham số cho phương thức hoặc giá trị trả về từ phương thức.
Times.Exactly(1)
và nó không thất bại khi phương thức thực tế được gọi hai lần. Chỉ sau khi thêm Setup
phương thức được đề cập, nó mới không thành công.
Bộ điều khiển kiểm tra có thể là:
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);
}
Và khi phương thức DeleteCars được gọi với id hợp lệ, thì chúng tôi có thể xác minh rằng, phương thức loại bỏ Dịch vụ được gọi chính xác một lần bằng bài kiểm tra này:
[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));
}