Cara menggunakan Moq untuk memudahkan pengujian unit di C #

Kita sering perlu menulis ujian unit untuk kod yang mengakses sumber luaran seperti pangkalan data atau sistem fail fail. Sekiranya sumber daya tersebut tidak tersedia, satu-satunya cara untuk memastikan ujian dapat dilaksanakan adalah dengan membuat objek tiruan. Pada dasarnya, dengan menggunakan implementasi palsu dari kebergantungan yang mendasari ini, anda dapat menguji interaksi antara kaedah yang diuji dan kebergantungannya. Tiga daripada kerangka ejekan yang paling popular untuk pembangun. Net adalah Rhino Mocks, Moq, dan NMock.

Antaranya, Moq mungkin yang paling fleksibel dan mudah digunakan. Rangka kerja Moq menyediakan cara elegan untuk mengatur, menguji, dan mengesahkan ejekan. Artikel ini membentangkan perbincangan mengenai Moq dan bagaimana ia dapat digunakan untuk mengasingkan unit kod dari pergantungan mereka.

Bermula dengan Moq

Anda boleh menggunakan Moq untuk membuat objek tiruan yang mensimulasikan atau meniru objek sebenar. Moq boleh digunakan untuk mengejek kelas dan antara muka. Walau bagaimanapun, terdapat beberapa batasan yang harus anda ketahui. Kelas yang akan diejek tidak boleh statik atau dimeteraikan, dan kaedah yang diejek harus ditandai sebagai maya. (Perhatikan ada penyelesaian untuk sekatan ini. Anda boleh mengejek kaedah statik dengan memanfaatkan corak reka bentuk penyesuai, misalnya.)

Langkah pertama dalam menggunakan Moq adalah memasangnya sehingga anda dapat menggunakannya dalam projek ujian unit anda. Anda boleh memuat turun Moq dari GitHub dan menambahkan rujukan yang sesuai. Namun, saya lebih suka memasang Moq melalui NuGet kerana kedua-duanya lebih mudah dan tidak mungkin terlepas rujukan. Anda boleh memasang Moq dengan menggunakan perintah berikut di baris perintah NuGet.

Install-Package Moq

Cara mengejek antaramuka menggunakan Moq

Mari mulakan dengan mengejek antara muka. Sintaks untuk membuat objek tiruan menggunakan kelas Mock diberikan di bawah.

Mock mockObjectType = ejekan baru ();

Sekarang, pertimbangkan antara muka berikut bernama IAuthor.

antara muka awam IAuthor

    {

        int Id {dapatkan; menetapkan; }

        rentetan FirstName {get; menetapkan; }

        rentetan LastName {get; menetapkan; }

    }

Dengan menggunakan rangka kerja Moq, anda dapat membuat objek tiruan, menetapkan nilai harta benda, menentukan parameter, dan mengembalikan nilai pada kaedah panggilan. Coretan kod berikut menggambarkan bagaimana anda dapat membuat sebuah instance dari antara muka IAuthor menggunakan Moq.

var mock = ejekan baru ();

Perhatikan bahawa kelas Mock tergolong dalam rangka kerja Moq dan mengandungi konstruktor generik yang menerima jenis antara muka yang ingin anda buat. Moq memanfaatkan ungkapan lambda, perwakilan, dan generik. Semua ini menjadikan penggunaan kerangka kerja sangat intuitif.

Coretan kod berikut menunjukkan bagaimana anda dapat mengejek antarmuka IAuthor dan memberikan nilai-nilai contoh tiruan dengan nilai yang sesuai. Perhatikan bagaimana kita menggunakan Assert untuk mengesahkan nilai-nilai sifat instance yang diejek.

var author = ejekan baru ();

pengarang.SetupGet (p => p.Id). Kembalinya (1);

author.SetupGet (p => p.FirstName) .Pulangan ("Joydip");

author.SetupGet (p => p.LastName). Kembalinya (“Kanjilal”);

Assert.AreEqual ("Joydip", pengarang.Object.FirstName);

Assert.AreEqual ("Kanjilal", pengarang.Object.LastName);

Cara mengejek kaedah menggunakan Moq

Sekarang mari kita pertimbangkan kelas berikut bernama Artikel. Kelas Artikel mengandungi hanya satu kaedah yang disebut GetPublicationDate yang menerima Id artikel sebagai parameter dan mengembalikan tarikh penerbitan artikel.

Artikel kelas awam

    {

        DateTime GetPublicationDate maya awam (int artikelId)

        {

            membuang NotImplementedException baru ();

        }

    }

Oleh kerana kaedah GetPublicationDate belum dilaksanakan di kelas Artikel, metode tersebut telah diejek untuk mengembalikan tanggal saat ini sebagai tanggal penerbitan, seperti yang ditunjukkan dalam potongan kode yang diberikan di bawah.

var mockObj = ejekan baru ();
mockObj.Setup (x => x.GetPublicationDate (It.IsAny ())). Returns ((int x) => DateTime.Now);

Kaedah Penyediaan digunakan untuk menentukan tingkah laku kaedah yang diteruskan kepadanya sebagai parameter. Dalam contoh ini, ia digunakan untuk menentukan tingkah laku kaedah GetPublicationDate. Panggilan untuk It.IsAny()menunjukkan bahawa kaedah GetPublicationDate akan menerima parameter jenis bilangan bulat; Itmerujuk kepada kelas statik. Kaedah Returns digunakan untuk menentukan nilai kembali dari kaedah yang ditentukan dalam panggilan kaedah Setup. Dalam contoh ini, kaedah Returns digunakan untuk menentukan nilai pengembalian kaedah sebagai tarikh sistem semasa.

Moq membolehkan anda mengesahkan sama ada kaedah atau harta tanah tertentu dipanggil. Coretan kod berikut menggambarkan perkara ini.

mockObj.Verify (t => t.GetPublicationDate (It.IsAny ()));

Di sini kita menggunakan kaedah Verify untuk menentukan sama ada GetPublicationDate dipanggil pada objek tiruan.

Cara mengejek kaedah kelas asas menggunakan Moq

Pertimbangkan sekeping kod berikut. Kami mempunyai dua kelas di sini - kelas RepositoryBase dan kelas AuthorRepository yang memperluasnya.

RepositoryBase kelas abstrak awam

{

    bool maya awam IsServiceConnectionValid ()

    {

        // Beberapa kod

    }

}

kelas awam AuthorRepository: RepositoryBase

{

    kekosongan awam Simpan ()

    {

        jika (IsServiceConnectionValid ())

        {

            // Beberapa kod

        }

    }

}

Sekarang andaikan kita ingin memeriksa sama ada sambungan pangkalan data itu sah. Namun, kami mungkin tidak mahu menguji semua kod di dalam kaedah IsServiceConnectionValid. Contohnya, kaedah IsServiceConnectionValid mungkin mengandungi kod yang berkaitan dengan perpustakaan pihak ketiga. Kami tidak mahu mengujinya, bukan? Di sinilah kaedah CallBase di Moq dapat menyelamatkannya. 

Dalam situasi seperti ini, di mana anda mempunyai kaedah di kelas asas yang telah diganti dengan jenis tiruan, dan anda perlu mengejek versi dasar kaedah yang diganti sahaja, anda boleh menggunakan CallBase. Coretan kod berikut menunjukkan bagaimana anda dapat membuat objek tiruan separa dari kelas AuthorRepository dengan menetapkan sifat CallBase ke true.

var mockObj = ejekan baru () {CallBase = true};

mockObj.Setup (x => x.IsServiceConnectionValid ()). Pulangan (benar);

Rangka kerja Moq memudahkan untuk membuat objek tiruan yang meniru tingkah laku kelas dan antara muka untuk diuji, hanya dengan fungsi yang anda perlukan. Untuk maklumat lanjut mengenai mengejek, lihat artikel hebat dari Martin Fowler ini.