Menggunakan Moq untuk menentukan apakah suatu metode dipanggil

159

Ini adalah pemahaman saya bahwa saya dapat menguji bahwa pemanggilan metode akan terjadi jika saya memanggil metode tingkat yang lebih tinggi, yaitu:

public abstract class SomeClass()
{    
    public void SomeMehod()
    {
        SomeOtherMethod();
    }

    internal abstract void SomeOtherMethod();
}

Saya ingin menguji bahwa jika saya menelepon SomeMethod()maka saya berharap itu SomeOtherMethod()akan dipanggil.

Apakah saya benar berpikir tes semacam ini tersedia dalam kerangka mengejek?

Owen
sumber

Jawaban:

186

Anda dapat melihat apakah suatu metode dalam sesuatu yang Anda tiru telah dipanggil dengan menggunakan Verifikasi, misalnya:

static void Main(string[] args)
{
        Mock<ITest> mock = new Mock<ITest>();

        ClassBeingTested testedClass = new ClassBeingTested();
        testedClass.WorkMethod(mock.Object);

        mock.Verify(m => m.MethodToCheckIfCalled());
}

class ClassBeingTested
{
    public void WorkMethod(ITest test)
    {
        //test.MethodToCheckIfCalled();
    }
}

public interface ITest
{
    void MethodToCheckIfCalled();
}

Jika saluran dibiarkan dikomentari, itu akan melempar MockException saat Anda menelepon Verifikasi. Jika tidak dikomando, akan berlalu.

Paul
sumber
7
Ini jawaban yang benar. Anda harus memahami sesuatu. Anda TIDAK BISA mengejek metode / properti yang tidak abstrak atau virtual (jelas, semua metode dan properti antarmuka dapat diejek).
25
-1: .Expect (...). Verifiable () berlebihan dalam kode ini. Menggunakan AAA, verifikasi yang Anda miliki tepat. .Verifiable untuk penggunaan dengan .Verify () i, .e. versi no arg. Lihat stackoverflow.com/questions/980554/…
Ruben Bartelink
@ I - ya itu bisa
reggaeguitar
6

Tidak, pengujian tiruan mengasumsikan Anda menggunakan pola desain tertentu yang dapat diuji, salah satunya adalah injeksi. Dalam kasus Anda, Anda akan menguji SomeClass.SomeMethod dan SomeOtherMethodharus diimplementasikan di entitas lain yang perlu dihubungkan.

SomeclassKonstruktor Anda akan terlihat seperti New(ISomeOtherClass). Kemudian Anda akan mengejek ISomeOtherClassdan menetapkan harapan SomeOtherMethoduntuk dipanggil dan memverifikasi harapan.

Val
sumber
0

Meskipun saya setuju bahwa jawaban @ Paul adalah cara yang disarankan untuk pergi, saya hanya ingin menambahkan satu cara alternatif yang disediakan oleh moqdiri sendiri.

Sejak SomeClassadalah abstractmemang mockable, tapi public void SomeMehod()tidak. Intinya adalah menemukan cara untuk mengejek dan entah bagaimana memanggil metode itu dan kemudian menggunakan CallBasemenyebarkan panggilan ke Internet SomeOtherMethod(). Mungkin terdengar seperti retasan tetapi intinya sederhana. Ini dapat digunakan dalam kasus jika refactoring yang diusulkan tidak dimungkinkan.

// This class is used only for test and purpose is make SomeMethod mockable
public abstract class DummyClass : SomeClass
{
    public virtual void DummyMethod() => base.SomeMethod();
}

Kemudian Anda dapat mengatur DummyMethod()untuk menyebarkan panggilan dengan mengatur CallBasebendera.

//Arrange
var mock = new Mock<DummyClass>();
mock.Setup(m => m.DummyMethod()).CallBase();

//Act
mock.Object.SomeMethod();

//Assert
mock.Verify(m => m.SomeOtherMethod(), Times.Once);
Johnny
sumber
Diturunkan karena lebih rumit dan membutuhkan boilerplate DummyClass
reggaeguitar
terbalik karena kadang-kadang Anda tidak dapat melakukan refactor dan Anda perlu menguji pelaksanaannya
wickdninja