Moq ile bir yöntemin tam olarak bir kez çağrıldığını nasıl doğrularım?


112

Moq ile bir yöntemin tam olarak bir kez çağrıldığını nasıl doğrularım? Verify()Vs Verifable()olayı gerçekten kafa karıştırıcı.

Yanıtlar:


165

Sen kullanabilirsiniz Times.Once()veya Times.Exactly(1):

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

İşte Times sınıfındaki yöntemler :

  • AtLeast - Sahte bir yöntemin en az kez çağrılması gerektiğini belirtir.
  • AtLeastOnce - Sahte bir yöntemin en az bir kez çağrılması gerektiğini belirtir.
  • AtMost - Sahte bir yöntemin maksimum süre olarak çağrılması gerektiğini belirtir.
  • AtMostOnce - Sahte bir yöntemin en fazla bir kez çağrılması gerektiğini belirtir.
  • Between - Alay edilen bir yöntemin from ve to times arasında çağrılması gerektiğini belirtir.
  • Exactly - Alay edilen bir yöntemin tam olarak kez çağrılması gerektiğini belirtir.
  • Never - Sahte bir yöntemin çağrılmaması gerektiğini belirtir.
  • Once - Alay edilen bir yöntemin tam olarak bir kez çağrılması gerektiğini belirtir.

Sadece bunların yöntem çağrıları olduğunu unutmayın; Onların mülk olduğunu düşünerek ve parantezleri unutarak takılmaya devam ettim.


2
öyleyse mockContext'i nasıl alırsınız / kurarsınız?
Choco

2
@Choco Sanırım bu onun Mock örneği. Yani bunu var mockContext = new Mock<IContext>()ayarlamak gibi bir şeydi .
Zack Huber

Sadece merak AtLeast, AtMost, Between, veya Exactlymülk olarak görülebilir. Demek istediğim, bir şey yapmak için bir parametreye ihtiyaçları var.
Danylo Yelizarov

8

2 tamsayı eklemek için bir yöntemle bir hesap makinesi oluşturduğumuzu hayal edin. İhtiyacın, add yöntemi çağrıldığında, print yöntemini bir kez çağırdığını hayal edelim. İşte bunu nasıl test edeceğimiz:

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

Ve burada daha fazla açıklama için kod içinde yorumların bulunduğu gerçek test var:

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

Not : Varsayılan olarak Moq, siz bir Mock nesnesi oluşturduğunuz anda tüm özellikleri ve yöntemleri saplayacaktır. Böylece, arama Setupyapmasanız bile , Moq yöntemlerini çoktan başlattı, IPrinterböylece sadece arayabilirsiniz Verify. Bununla birlikte, iyi bir uygulama olarak, her zaman bunu kurarım çünkü belirli beklentileri karşılamak için metoda parametreleri veya belirli beklentileri karşılamak için metottan elde edilen dönüş değerini veya kaç kez çağrıldığını zorlamamız gerekebilir.


Ben çağırıyordu Verify, Times.Oncehiç uğramadan Setup. VerifyBu durumda kesinlikle patlamayı beklerdim , ama olmadı.
dudeNumber4

@ dudeNumber4 Hayır patlamaz çünkü varsayılan olarak Moq siz bir Mocknesne yaratır oluşturmaz tüm özellikleri ve yöntemleri saplayacaktır . Böylece, arama Setupyapmasanız bile , Moq yöntemlerini çoktan başlattı, IPrinterböylece sadece arayabilirsiniz Verify. Bununla birlikte, iyi bir uygulama olarak, her zaman ayarladım çünkü parametreleri yönteme veya yöntemden dönüş değerini zorlamamız gerekebilir.
CodingYoshi

Üzgünüm, bu korkunç bir açıklamaydı. Aradım Times.Exactly(1)ve yöntem aslında iki kez çağrıldığında başarısız olmadı . Ancak Setupsöz konusu yöntem için eklendikten sonra doğru şekilde başarısız oldu.
dudeNumber4

2

Test kontrolörü şunlar olabilir:

  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 yöntemi geçerli bir id ile çağrıldığında, bu test tarafından tam olarak bir kez çağrılan Service remove yöntemini doğrulayabiliriz:

 [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));
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.