Comment vérifier qu'une méthode a été appelée exactement une fois avec Moq? La chose Verify()
contre Verifable()
est vraiment déroutante.
Comment vérifier qu'une méthode a été appelée exactement une fois avec Moq? La chose Verify()
contre Verifable()
est vraiment déroutante.
Réponses:
Vous pouvez utiliser Times.Once()
, ou Times.Exactly(1)
:
mockContext.Verify(x => x.SaveChanges(), Times.Once());
mockContext.Verify(x => x.SaveChanges(), Times.Exactly(1));
Voici les méthodes de la classe Times :
AtLeast
- Spécifie qu'une méthode simulée doit être invoquée au minimum.AtLeastOnce
- Spécifie qu'une méthode simulée doit être appelée une fois au minimum.AtMost
- Spécifie qu'une méthode simulée doit être invoquée au maximum.AtMostOnce
- Spécifie qu'une méthode simulée doit être invoquée une fois au maximum.Between
- Spécifie qu'une méthode simulée doit être invoquée entre les heures de et à.Exactly
- Spécifie qu'une méthode simulée doit être invoquée exactement fois fois.Never
- Spécifie qu'une méthode simulée ne doit pas être appelée.Once
- Spécifie qu'une méthode simulée doit être appelée exactement une fois.N'oubliez pas que ce sont des appels de méthode; Je n'arrêtais pas de trébucher, pensant que c'étaient des propriétés et oubliant les parenthèses.
var mockContext = new Mock<IContext>()
mettre en place cela.
AtLeast
, AtMost
, Between
ou Exactly
pourrait être considéré comme la propriété. Je veux dire, ils ont évidemment besoin d'un paramètre pour faire quelque chose.
Imaginez que nous construisons une calculatrice avec une méthode pour ajouter 2 entiers. Imaginons en outre que l'exigence est que lorsque la méthode add est appelée, elle appelle la méthode print une fois. Voici comment nous testerions ceci:
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);
}
}
Et voici le test réel avec des commentaires dans le code pour plus de précisions:
[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);
}
}
Remarque : Par défaut, Moq stub de toutes les propriétés et méthodes dès que vous créez un objet Mock. Donc, même sans appeler Setup
, Moq a déjà stubé les méthodes pour IPrinter
que vous puissiez simplement appeler Verify
. Cependant, comme bonne pratique, je la configure toujours car nous pouvons avoir besoin d'appliquer les paramètres de la méthode pour répondre à certaines attentes, ou la valeur de retour de la méthode pour répondre à certaines attentes ou le nombre de fois qu'elle a été appelée.
Verify
, Times.Once
sans jamais appeler Setup
. Je m'attendrais certainement Verify
à exploser dans ce cas, mais ce n'est pas le cas.
Mock
objet. Donc, même sans appeler Setup
, Moq a déjà stubé les méthodes pour IPrinter
que vous puissiez simplement appeler Verify
. Cependant, comme bonne pratique, je le configure toujours car nous pouvons avoir besoin d'appliquer les paramètres à la méthode ou la valeur de retour de la méthode.
Times.Exactly(1)
et cela n'a pas échoué lorsque la méthode a en fait été appelée deux fois. Ce n'est qu'après l'ajout Setup
de la méthode en question qu'elle a échoué correctement.
Le contrôleur de test peut être:
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);
}
Et lorsque la méthode DeleteCars est appelée avec un identifiant valide, nous pouvons le vérifier, la méthode de suppression du service appelée exactement une fois par ce test:
[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));
}