Wie überprüfe ich, ob eine Methode mit Moq genau einmal aufgerufen wurde? Das Verify()
vs. Verifable()
Ding ist wirklich verwirrend.
Wie überprüfe ich, ob eine Methode mit Moq genau einmal aufgerufen wurde? Das Verify()
vs. Verifable()
Ding ist wirklich verwirrend.
Antworten:
Sie können verwenden Times.Once()
, oder Times.Exactly(1)
:
mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));
Hier sind die Methoden für die Times- Klasse:
AtLeast
- Gibt an, dass eine verspottete Methode mindestens mal aufgerufen werden soll.AtLeastOnce
- Gibt an, dass eine verspottete Methode mindestens einmal aufgerufen werden soll.AtMost
- Gibt an, dass eine verspottete Methode maximal mal aufgerufen werden soll.AtMostOnce
- Gibt an, dass eine verspottete Methode maximal einmal aufgerufen werden soll.Between
- Gibt an, dass eine verspottete Methode zwischen von und bis zu Zeiten aufgerufen werden soll.Exactly
- Gibt an, dass eine verspottete Methode genau mal aufgerufen werden soll.Never
- Gibt an, dass eine verspottete Methode nicht aufgerufen werden soll.Once
- Gibt an, dass eine verspottete Methode genau einmal aufgerufen werden soll.Denken Sie daran, dass es sich um Methodenaufrufe handelt. Ich stolperte immer wieder, dachte, sie seien Eigenschaften und vergaß die Klammern.
var mockContext = new Mock<IContext>()
das einzurichten.
AtLeast
, AtMost
, Between
oder Exactly
als Objekt angesehen werden könnten. Ich meine, sie brauchen einen Parameter, um etwas zu tun.
Stellen Sie sich vor, wir bauen einen Taschenrechner mit einer Methode zum Hinzufügen von 2 ganzen Zahlen. Stellen wir uns weiter vor, die Anforderung besteht darin, dass beim Aufrufen der add-Methode die print-Methode einmal aufgerufen wird. So würden wir das testen:
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);
}
}
Und hier ist der eigentliche Test mit Kommentaren im Code zur weiteren Verdeutlichung:
[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);
}
}
Hinweis : Standardmäßig stoppt Moq alle Eigenschaften und Methoden, sobald Sie ein Mock-Objekt erstellen. Auch ohne Aufruf Setup
hat Moq die Methoden bereits blockiert, IPrinter
sodass Sie einfach aufrufen können Verify
. Als bewährte Methode habe ich sie jedoch immer eingerichtet, da wir möglicherweise die Parameter für die Methode erzwingen müssen, um bestimmte Erwartungen zu erfüllen, oder den Rückgabewert der Methode, um bestimmte Erwartungen zu erfüllen, oder die Häufigkeit, mit der sie aufgerufen wurde.
Verify
, Times.Once
ohne jemals anzurufen Setup
. Ich würde sicherlich erwarten Verify
, in diesem Fall in die Luft zu jagen, aber das tat es nicht.
Mock
Objekt erstellen . Auch ohne Aufruf Setup
hat Moq die Methoden bereits blockiert, IPrinter
sodass Sie einfach aufrufen können Verify
. Als gute Vorgehensweise habe ich es jedoch immer eingerichtet, da wir möglicherweise die Parameter für die Methode oder den Rückgabewert der Methode erzwingen müssen.
Times.Exactly(1)
und es ist nicht fehlgeschlagen, als die Methode tatsächlich zweimal aufgerufen wurde. Erst nach dem Hinzufügen Setup
für die betreffende Methode ist sie korrekt fehlgeschlagen.
Testcontroller kann sein:
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);
}
Und wenn die DeleteCars-Methode mit einer gültigen ID aufgerufen wird, können wir überprüfen, ob die Dienstentfernungsmethode bei diesem Test genau einmal aufgerufen wurde:
[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));
}