Bagaimana cara memverifikasi bahwa metode dipanggil tepat sekali dengan Moq?

112

Bagaimana cara memverifikasi bahwa metode dipanggil tepat sekali dengan Moq? Hal Verify()vs. Verifable()benar-benar membingungkan.

Josh Kodroff
sumber

Jawaban:

165

Anda dapat menggunakan Times.Once(), atau Times.Exactly(1):

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

Berikut adalah metode di kelas Times :

  • AtLeast - Menentukan bahwa metode tiruan harus dipanggil sesingkat mungkin.
  • AtLeastOnce - Menentukan bahwa metode tiruan harus dipanggil minimal satu kali.
  • AtMost - Menentukan bahwa metode tiruan harus dipanggil waktu maksimum.
  • AtMostOnce - Menentukan bahwa metode tiruan harus dipanggil satu kali sebagai maksimum.
  • Between - Menentukan bahwa metode tiruan harus dipanggil antara dari dan ke waktu.
  • Exactly - Menentukan bahwa metode tiruan harus dipanggil tepat waktu.
  • Never - Menentukan bahwa metode tiruan tidak boleh dipanggil.
  • Once - Menentukan bahwa metode tiruan harus dipanggil tepat satu kali.

Ingatlah bahwa mereka adalah pemanggilan metode; Saya terus tersandung, mengira itu properti dan melupakan tanda kurung.

Jeff Ogata
sumber
2
jadi bagaimana Anda mendapatkan / menyiapkan mockContext?
Choco
2
@Choco Saya berasumsi itu hanya contoh Mock-nya. Jadi itu seperti var mockContext = new Mock<IContext>()mengaturnya.
Zack Huber
Aku hanya ingin tahu bagaimana AtLeast, AtMost, Between, atau Exactlybisa dilihat sebagai properti. Maksud saya, mereka pasti membutuhkan parameter untuk melakukan sesuatu.
Danylo Yelizarov
8

Bayangkan kita sedang membangun kalkulator dengan satu metode untuk menambahkan 2 bilangan bulat. Mari kita bayangkan lebih lanjut persyaratannya adalah ketika metode add dipanggil, ia memanggil metode cetak sekali. Berikut adalah cara kami menguji ini:

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

Dan inilah tes sebenarnya dengan komentar di dalam kode untuk klarifikasi lebih lanjut:

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

Catatan : Secara default Moq akan menghentikan semua properti dan metode segera setelah Anda membuat objek Mock. Jadi bahkan tanpa menelepon Setup, Moq telah mematikan metode IPrintersehingga Anda bisa menelepon Verify. Namun, sebagai praktik yang baik, saya selalu menyiapkannya karena kita mungkin perlu menerapkan parameter ke metode untuk memenuhi ekspektasi tertentu, atau nilai kembalian dari metode untuk memenuhi ekspektasi tertentu atau berapa kali ia dipanggil.

CodingYoshi
sumber
Saya menelepon Verify, Times.Oncetanpa pernah menelepon Setup. Saya pasti berharap Verifyuntuk meledak dalam kasus itu, tetapi ternyata tidak.
dudeNumber4
@ dudeNumber4 Tidak itu tidak akan meledak karena secara default Moq akan menghentikan semua properti dan metode segera setelah Anda membuat Mockobjek. Jadi bahkan tanpa menelepon Setup, Moq telah mematikan metode IPrintersehingga Anda bisa menelepon Verify. Namun, sebagai praktik yang baik, saya selalu menyiapkannya karena kita mungkin perlu menerapkan parameter ke metode atau nilai kembalian dari metode tersebut.
CodingYoshi
Maaf, itu penjelasan yang buruk. Saya menelepon Times.Exactly(1)dan tidak gagal ketika metode itu sebenarnya dipanggil dua kali. Hanya setelah menambahkan Setupmetode yang dimaksud apakah itu gagal dengan benar.
dudeNumber4
2

Pengontrol uji dapat berupa:

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

Dan ketika metode DeleteCars dipanggil dengan id yang valid, maka kita dapat memverifikasi itu, Metode penghapusan layanan dipanggil tepat sekali oleh tes ini:

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