Kerangka kerja tiruan vs kerangka kerja MS Fakes

99

Agak bingung dengan perbedaan framework Mock seperti NMock vs Framework Fakes VS 2011. Melalui MSDN, yang saya mengerti adalah bahwa Fakes memungkinkan Anda untuk mengejek dependensi Anda seperti RhinoMock atau NMock, namun pendekatannya berbeda, Fakes menghasilkan kode untuk mencapai fungsi ini tetapi kerangka Mocks tidak. Jadi apakah pemahaman saya benar? Apakah Palsu hanyalah kerangka kerja Mock

Nairooz NIlafdeen
sumber

Jawaban:

189

Pertanyaan Anda adalah tentang bagaimana kerangka kerja MS Fakes berbeda dari NMock dan tampaknya jawaban lain telah menyelesaikan beberapa di antaranya, tetapi berikut adalah beberapa informasi lebih lanjut tentang bagaimana mereka sama dan bagaimana perbedaannya. NMock juga mirip dengan RhinoMocks dan Moq, jadi saya mengelompokkan mereka dengan NMock.

Ada 3 perbedaan utama yang saya lihat langsung antara NMock / RhinoMocks / Moq dan MS Fakes Framework:

  • Kerangka palsu MS menggunakan kode yang dihasilkan, seperti Accessors di versi Visual Studio sebelumnya, bukan tipe generik. Saat Anda ingin menggunakan kerangka kerja palsu untuk sebuah ketergantungan, Anda menambahkan rakitan yang berisi ketergantungan ke referensi proyek uji dan kemudian klik kanan padanya untuk menghasilkan uji ganda (rintisan atau shims). Kemudian saat Anda menguji, Anda sebenarnya menggunakan kelas yang dihasilkan ini sebagai gantinya. NMock menggunakan obat generik untuk mencapai hal yang sama (yaitu IStudentRepository studentRepository = mocks.NewMock<IStudentRepository>()). Menurut pendapat saya, pendekatan kerangka kerja MS Fakes menghambat navigasi kode dan pemfaktoran ulang dari dalam pengujian karena Anda benar-benar bekerja dengan kelas yang dihasilkan, bukan antarmuka asli Anda.

  • Kerangka palsu MS menyediakan rintisan dan tahi lalat (shims), sedangkan NMock, RhinoMocks, dan Moq semuanya menyediakan rintisan dan tiruan . Saya benar-benar tidak mengerti keputusan MS untuk tidak memasukkan ejekan dan saya, secara pribadi bukan penggemar tahi lalat karena alasan yang dijelaskan di bawah ini.

  • Dengan kerangka kerja palsu MS, Anda menyediakan implementasi alternatif dari metode yang ingin Anda stub. Dalam implementasi alternatif ini, Anda dapat menentukan nilai yang dikembalikan dan melacak informasi tentang bagaimana atau jika metode itu dipanggil. Dengan NMock, RhinoMocks dan Moq, Anda menghasilkan objek tiruan dan kemudian menggunakan objek tersebut untuk menentukan nilai kembali yang dipotong atau untuk melacak interaksi (apakah dan bagaimana metode itu dipanggil). Saya menemukan pendekatan MS palsu lebih kompleks dan kurang ekspresif.

Untuk memperjelas perbedaan dalam apa yang disediakan kerangka kerja: NMock, RhinoMocks dan Moq semuanya menyediakan dua jenis tes ganda (rintisan dan tiruan). Kerangka palsu menyediakan rintisan dan tahi lalat (mereka menyebutnya shims), dan sayangnya tidak menyertakan tiruan. Untuk memahami perbedaan dan persamaan antara NMock dan MS Fakes, akan sangat membantu untuk memahami apa jenis tes ganda ini:

Stubs: Stub digunakan saat Anda perlu memberikan nilai untuk metode atau properti yang akan ditanyakan pada pengujian ganda Anda dengan metode yang diuji. Misalnya, ketika metode saya yang sedang diuji memanggil metode DoesStudentExist () dari tes ganda IStudentRepository, saya ingin mengembalikan nilai true.

Ide stubs di NMock dan MS palsu adalah sama, tetapi dengan NMock Anda akan melakukan sesuatu seperti ini:

Stub.On(mockStudentRepository).Method("DoesStudentExist").Will(Return.Value(true));

Dan dengan MSFakes Anda akan melakukan sesuatu seperti ini:

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() // Generated by Fakes.
{
    DoesStudentExistInt32 = (studentId) => { return new Student(); }
};

Perhatikan dalam contoh MS Fakes Anda membuat implementasi yang sama sekali baru untuk metode DoesStudentExist (Perhatikan bahwa ini disebut DoesStudentExistInt32 karena kerangka palsu menambahkan tipe data parameter ke nama metode saat menghasilkan objek rintisan, saya pikir ini mengaburkan kejelasan tes). Sejujurnya implementasi NMock juga mengganggu saya karena menggunakan string untuk mengidentifikasi nama metode. (Maafkan saya jika saya salah memahami bagaimana NMock dimaksudkan untuk digunakan.) Pendekatan ini benar-benar menghambat refactoring dan saya sangat merekomendasikan RhinoMocks atau Moq daripada NMock karena alasan ini.

Tiruan: Tiruan digunakan untuk memverifikasi interaksi antara metode Anda yang sedang diuji dan dependensinya. Dengan NMock, Anda melakukan ini dengan menetapkan ekspektasi yang serupa dengan ini:

Expect.Once.On(mockStudentRepository).Method("Find").With(123);

Ini adalah alasan lain mengapa saya lebih memilih RhinoMocks dan Moq daripada NMock, NMock menggunakan gaya ekspektasi yang lebih tua sedangkan RhinoMocks dan Moq keduanya mendukung pendekatan Atur / Bertindak / Tegaskan di mana Anda menentukan interaksi yang Anda harapkan sebagai pernyataan di akhir tes seperti ini :

stubStudentRepository.AssertWasCalled( x => x.Find(123));

Sekali lagi, perhatikan bahwa RhinoMocks menggunakan lambda, bukan string untuk mengidentifikasi metode tersebut. Kerangka ms fakes tidak menyediakan tiruan sama sekali. Ini berarti bahwa dalam implementasi yang dihentikan (lihat deskripsi stub di atas), Anda harus menyetel variabel yang nanti Anda verifikasi telah disetel dengan benar. Itu akan terlihat seperti ini:

bool wasFindCalled = false;

IStudentRepository studentRepository = new DataAccess.Fakes.StubIStudentRepository() 
{
    DoesStudentExistInt32 = (studentId) => 
        { 
            wasFindCalled = true;
            return new Student(); 
        }
};

classUnderTest.MethodUnderTest();

Assert.IsTrue(wasFindCalled);

Saya menemukan pendekatan ini menjadi sedikit berbelit-belit karena Anda harus melacak panggilan di rintisan dan kemudian menegaskannya nanti dalam pengujian. Saya menemukan NMock, dan terutama RhinoMock, sebagai contoh yang lebih ekspresif.

Tahi Lalat (Shims): Terus terang, saya tidak suka tahi lalat, karena potensi mereka untuk disalahgunakan. Salah satu hal yang sangat saya sukai tentang pengujian unit (dan khususnya TDD) adalah pengujian kode Anda membantu Anda memahami di mana Anda telah menulis kode yang buruk. Ini karena pengujian kode yang ditulis dengan buruk itu sulit. Ini tidak benar saat menggunakan mol karena mol sebenarnya dirancang untuk memungkinkan Anda menguji dependensi yang tidak diinjeksi atau untuk menguji metode privat. Cara kerjanya mirip dengan stub, kecuali Anda menggunakan ShimsContext seperti ini:

using (ShimsContext.Create())
{
    System.Fakes.ShimDateTime.NowGet = () => { return new DateTime(fixedYear, 1, 1); };
}

Kekhawatiran saya dengan shims adalah bahwa orang akan mulai melihat mereka sebagai "cara yang lebih mudah untuk pengujian unit" karena tidak memaksa Anda untuk menulis kode seperti yang seharusnya. Untuk tulisan yang lebih lengkap tentang konsep ini lihat posting saya ini:

Untuk informasi lebih lanjut tentang beberapa masalah yang terkait dengan kerangka palsu, lihat posting ini:

Jika Anda tertarik untuk mempelajari RhinoMocks, berikut adalah video pelatihan Pluralsight (pengungkapan penuh - Saya menulis kursus ini dan mendapatkan royalti untuk penayangan, tetapi menurut saya ini berlaku untuk diskusi ini, jadi saya memasukkannya di sini):

Jim Cooper
sumber
14
@Jim Saya tidak setuju bahwa mengizinkan seseorang untuk "menguji ketergantungan yang tidak disuntikkan" adalah hal yang buruk. Sebaliknya, dalam praktiknya, kemampuan ini membantu menghindari kekacauan basis kode dengan banyak antarmuka yang tidak berguna dan konfigurasi / kompleksitas "pengkabelan objek" yang terkait. Saya telah melihat beberapa proyek (baik Java dan .NET) yang memiliki ratusan antarmuka Java / C # dengan hanya satu kelas pelaksana, dan banyak konfigurasi XML yang tidak berguna (untuk kacang Spring DI, atau di Web.config untuk MS Unity kerangka). Dependensi seperti itu lebih baik tidak disuntikkan.
Rogério
19
@Rogerio, saya telah mengerjakan beberapa proyek dengan ribuan kelas yang mengikuti model ini dan ketika injeksi ketergantungan dilakukan dengan benar (jika Anda menggunakan konfigurasi XML Anda tidak melakukannya dengan benar, imho), itu sederhana dan relatif tidak menyakitkan. Di sisi lain, saya telah mengerjakan sistem yang tidak melakukan ini dan penggabungan antar kelas selalu menyebabkan rasa sakit yang signifikan bagi saya. Pengujian bukanlah alasan untuk menggunakan injeksi ketergantungan (meskipun itu bukan alasan yang buruk). Alasan sebenarnya adalah kopling yang kendor. Memiliki antarmuka yang diimplementasikan oleh satu kelas tidak pernah membuat saya kesakitan.
Jim Cooper
17
@Jim, saya melihat kemampuan untuk menguji desain yang buruk sebagai nilai tambah yang bagus. Hal pertama yang ingin Anda lakukan sebelum memfaktorkan ulang kode lama ke desain yang lebih baik adalah tes tulis.
Thomas Materna
4
Aturan saya adalah saya menggunakan Fakes hanya ketika saya harus menggunakan metode bersama / statis atau kelas yang saya tidak memiliki akses untuk mengimplementasikan antarmuka. Untuk yang lainnya saya menggunakan Moq. Pemalsuan lebih lambat (karena rakitan palsu perlu dibuat), dan dibutuhkan lebih banyak upaya pengkodean untuk mencocokkan fungsionalitas yang Anda dapatkan dengan Moq.
Nick
5
@ CarloV.Dango Pertama-tama, saya tahu betul bahwa Injeksi Ketergantungan tidak memerlukan antarmuka terpisah; komentar saya sebelumnya hanya menyinggung kecenderungan untuk membuat antarmuka seperti itu saat menggunakan DI. Kedua, "IOC" (Inversion of Control) tidak ada hubungannya dengan DI! (Yang pertama adalah tentang inversi aliran kontrol antar metode, sedangkan yang kedua adalah tentang resolusi dependensi untuk komponen / objek.) Dengan membingungkan IOC dan DI, Andalah yang menunjukkan ketidaktahuan, bukan saya; dan sejujurnya, situs ini tidak pantas dihina orang lain, jadi mohon, tetaplah sopan.
Rogério
23

Anda benar, tapi ada lebih banyak cerita. Hal terpenting yang dapat diambil dari jawaban ini adalah:

  1. Arsitektur Anda harus menggunakan rintisan dan injeksi ketergantungan yang tepat, daripada mengandalkan kruk palsu dan tiruan

  2. Palsu dan tiruan berguna untuk menguji kode yang tidak boleh atau tidak bisa Anda ubah, seperti:

    • Kode warisan yang tidak menggunakan (atau penggunaan yang efisien) dari rintisan
    • API pihak ketiga
    • Sumber daya yang kode sumbernya tidak Anda miliki

Shims (dikenal sebagai "Moles", selama pengembangan) memang merupakan kerangka kerja tiruan yang beroperasi dengan cara memutar panggilan. Alih-alih dengan susah payah membuat tiruan (ya, bahkan menggunakan Moq relatif menyakitkan!), Shims cukup menggunakan objek kode produksi yang sudah ada. Shim hanya merutekan ulang panggilan dari target produksi ke delegasi pengujian.

Rintisan dibuat dari antarmuka dalam proyek target. Objek Stub hanya itu - implementasi antarmuka. Manfaat menggunakan tipe Stub adalah Anda dapat dengan cepat membuat stub tanpa mengacaukan project pengujian Anda dengan banyak stub sekali pakai, belum lagi membuang-buang waktu untuk membuatnya. Tentu saja, Anda tetap harus membuat rintisan beton, untuk digunakan di banyak pengujian.

Menerapkan Fakes secara efisien (tipe Shims, Mocks, dan Stub) membutuhkan sedikit waktu untuk membiasakan diri, tetapi upaya ini sepadan. Saya pribadi telah menghemat waktu pengembangan selama berminggu-minggu, melalui penggunaan tipe Shims / Mole, Mocks, dan Stub. Saya harap Anda bersenang-senang dengan teknologi ini seperti saya!

Mike Christian
sumber
11
Diturunkan berdasarkan kurangnya spesifikasi dan beberapa masalah terminologi dengan komentar Anda di Fakes. Fakes adalah istilah umum untuk semua jenis tes ganda dan juga nama MS yang digunakan untuk perpustakaan palsu mereka. Di perpustakaan mereka hanya Shim yang sebenarnya adalah Tikus Tanah, bertopik bukan. Mengenai kebutuhan akan contoh, saya ingin melihat contoh dalam jawaban Anda yang menunjukkan bagaimana membuat shim (atau rintisan) dengan Fakes lebih sederhana daripada menggunakan Moq. Jika Anda membuat perubahan pada jawaban Anda untuk mengatasinya, saya akan mengubah suara negatif saya.
Jim Cooper
1
Tetapi menambahkan justifikasi yang baik untuk penggunaan shims (moles), yaitu kode pihak ketiga, API sistem / SDK. Ini bukan hanya tentang saat Anda bekerja dengan solusi internal Anda sendiri. Jadi saya akan memberi Anda satu suara untuk menyamakannya :-)
Tony Wall
2
@ Mike dan Jim .. Saya berusaha memperbaiki terminologi yang digunakan dalam jawaban ini. Tolong beri tahu saya jika kami bisa membuatnya lebih baik. Terima kasih.
Snesh
15

Seperti yang saya pahami, tim Visual Studio ingin menghindari persaingan dengan berbagai pustaka tiruan yang tersedia untuk .NET. MS sering menghadapi keputusan sulit seperti ini. Mereka dibendung jika tidak menyediakan fungsionalitas tertentu ("mengapa MS tidak memberi kami pustaka tiruan; tiruan adalah persyaratan yang umum?") Dan terkutuk jika mereka melakukannya ("mengapa Microsoft bertindak begitu agresif dan mendorongnya pendukung alami keluar dari pasar? ") Sangat sering, tetapi tidak selalu, mereka memutuskan untuk menahan diri dari sekadar memberikan alternatif mereka sendiri ke teknologi yang tersedia dan diterima dengan baik. Sepertinya itulah yang terjadi di sini.

Fitur shim dari Fakes benar-benar berguna. Tentu, ada bahayanya. Dibutuhkan beberapa disiplin untuk memastikan Anda hanya menggunakan ini jika diperlukan. Namun, itu mengisi celah besar. Keluhan utama saya adalah bahwa ini hanya dikirimkan dengan edisi Ultimate VS 2012 dan oleh karena itu hanya akan tersedia untuk sub-bagian dari komunitas pengembangan .NET. Sayang sekali.

Charles Young
sumber
2
Kerangka palsu juga tersedia dengan edisi Premium.
AlwaysAProgrammer
13

Pemalsuan mencakup dua jenis objek "palsu". Yang pertama, disebut "stub", pada dasarnya adalah dummy yang dibuat secara otomatis yang perilaku defaultnya dapat (dan biasanya akan) diganti untuk membuatnya menjadi tiruan yang lebih menarik. Namun, ia kekurangan beberapa fitur yang ditawarkan oleh sebagian besar kerangka kerja tiruan yang tersedia saat ini. Misalnya, jika Anda ingin memeriksa bahwa metode pada instance stub telah dipanggil, Anda perlu menambahkan logika untuk ini sendiri. Pada dasarnya, jika Anda membuat tiruan Anda sendiri secara manual sekarang, rintisan mungkin tampak seperti peningkatan. Namun, jika Anda sudah menggunakan kerangka kerja mocking berfitur lengkap, Anda mungkin merasa ada beberapa bagian penting yang hilang dari rintisan Fakes.

Kategori objek lain yang ditawarkan oleh Fakes, yang disebut "shim", memperlihatkan mekanisme untuk mengganti perilaku dependensi yang belum (atau tidak dapat) dipisahkan secara memadai untuk penggantian standar melalui tiruan. AFAIK, TypeMock adalah satu-satunya kerangka kerja tiruan utama yang saat ini menawarkan fungsionalitas semacam ini.

BTW, jika Anda telah mencoba Moles sebelumnya, Fakes pada dasarnya adalah hal yang sama, akhirnya keluar dari Microsoft Research dan menjadi produk yang sebenarnya.

Nicole Calinoiu
sumber
1
Pembaruan: Moles sekarang telah diintegrasikan ke dalam MS Fakes. "The Fakes Framework di Visual Studio 2012 adalah generasi berikutnya dari Moles & Stubs. Fakes berbeda dari Moles, bagaimanapun, jadi pindah dari Moles ke Fakes akan memerlukan beberapa modifikasi pada kode Anda. Kerangka Moles tidak akan didukung di Visual Studio 2012 . " Sumber: research.microsoft.com/en-us/projects/moles
Sire
1

Mengenai objek Fake (Shim + Stub), itu telah didefinisikan dengan baik di atas, meskipun saya rasa paragraf terakhir di komentar terakhir merangkum keseluruhan situasi dengan cukup baik.

Meskipun banyak orang akan berpendapat bahwa objek Fake (Shim + Stub) adalah aset yang baik untuk dimiliki dalam beberapa kasus pengujian unit, downside adalah bahwa tidak masalah jika Anda menggunakan Visual Studio 2012 atau Visual Studio 2013, opsi ini HANYA tersedia. dengan versi Premium atau Ultimate. IOW, ini berarti Anda TIDAK AKAN menjalankan SETIAP FAKE tersebut (Shim + Stub) pada versi Pro mana pun.

Anda mungkin melihat opsi menu Fakes (Shim + Stub) pada versi Pro, tetapi waspadalah, ada beberapa kemungkinan yang cukup kuat bahwa Anda tidak akan mendapatkan apa-apa ... Ini tidak akan menghasilkan kesalahan kompilasi yang memberi tahu Anda bahwa ada sesuatu yang penting. hilang, pilihan tidak ada, jadi jangan buang waktu Anda ...

Ini adalah faktor penting untuk dipertimbangkan dalam tim pengembang, terutama jika satu tim hanya menggunakan versi Ultimate sementara yang lain menggunakan versi Pro ... Moq di sisi lain dapat dengan mudah diinstal melalui Nuget tidak peduli versi Visual Studio yang Anda gunakan. Saya tidak punya masalah dalam menggunakan Moq, kunci dengan alat apa pun adalah mengetahui untuk apa mereka digunakan dan bagaimana menggunakannya dengan benar;)

SirXamelot
sumber
1
Harap format pertanyaan Anda ke dalam paragraf yang lebih kecil agar lebih mudah dibaca.
@SirXamelot, tidak memfaktorkan ulang kode Anda tidak dapat mengubah output dari .net menyediakan panggilan statis misalnya DateTime.Now atau Guid.NewGuid
zaitsman