Apa itu mengejek?

Jawaban:

598

Prolog: Jika Anda mencari kata benda tiruan dalam kamus Anda akan menemukan bahwa salah satu definisi kata adalah sesuatu yang dibuat sebagai tiruan .


Mengejek terutama digunakan dalam pengujian unit. Objek yang diuji mungkin memiliki ketergantungan pada objek lain (kompleks). Untuk mengisolasi perilaku objek Anda ingin mengganti objek lain dengan mengejek yang mensimulasikan perilaku objek nyata. Ini berguna jika objek nyata tidak praktis untuk dimasukkan ke dalam unit test.

Singkatnya, mengejek adalah menciptakan objek yang mensimulasikan perilaku objek nyata.


Kadang-kadang Anda mungkin ingin membedakan antara mengejek sebagai lawan dari stubbing . Mungkin ada beberapa ketidaksepakatan tentang subjek ini tetapi definisi saya tentang rintisan adalah objek simulasi "minimal". Stub mengimplementasikan perilaku yang cukup untuk memungkinkan objek yang diuji menjalankan tes.

Mock adalah seperti rintisan tetapi tes juga akan memverifikasi bahwa objek yang diuji memanggil mock seperti yang diharapkan. Bagian dari tes ini memverifikasi bahwa tiruan itu digunakan dengan benar.

Untuk memberikan contoh: Anda dapat mematikan database dengan menerapkan struktur memori sederhana untuk menyimpan catatan. Objek yang diuji kemudian dapat membaca dan menulis catatan ke pangkalan data database untuk memungkinkannya menjalankan tes. Ini dapat menguji beberapa perilaku objek yang tidak terkait dengan database dan stub basis data akan dimasukkan hanya untuk membiarkan tes berjalan.

Jika Anda ingin memverifikasi bahwa objek yang diuji menulis beberapa data spesifik ke database, Anda harus mengejek basis data. Tes Anda kemudian akan menggabungkan pernyataan tentang apa yang ditulis ke mock database.

Martin Liversage
sumber
18
Ini adalah jawaban yang baik, tetapi tidak perlu membatasi konsep mengejek objek . Mengganti "objek" dengan "unit" akan membuatnya lebih umum.
Rogério
1
Saya mengerti perbedaan dari rintisan vs mock. Satu-satunya hal adalah bahwa jika Anda menguji kasus Anda dengan rintisan dan itu lolos maka tidak dapatkah Anda menyimpulkan bahwa Anda sudah menggunakan rintisan maka Anda tidak lagi memerlukan verifikasi ?
Sayang
91

Jawaban lain menjelaskan apa itu mengejek. Biarkan saya membimbing Anda melaluinya dengan berbagai contoh . Dan percayalah, ini sebenarnya jauh lebih sederhana daripada yang Anda pikirkan.

tl; dr Ini adalah instance dari kelas asli. Ini memiliki data lain yang disuntikkan ke dalam sehingga Anda menghindari pengujian bagian yang disuntikkan dan hanya fokus pada pengujian rincian implementasi kelas / fungsi Anda.

Contoh sederhana:

class Foo {
    func add (num1: Int, num2: Int) -> Int { // Line A 
        return num1 + num2 // Line B
    }
}

let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)

Seperti yang Anda lihat, saya tidak menguji LineA yaitu saya tidak memvalidasi parameter input. Saya tidak memvalidasi untuk melihat apakah num1, num2 adalah Integer. Saya tidak menegaskan hal itu.

Saya hanya menguji untuk melihat apakah LineB ( implementasi saya ) memberikan nilai-nilai yang diejek 1dan 5melakukan seperti yang saya harapkan.

Jelas dalam kata sebenarnya ini bisa menjadi jauh lebih kompleks. Parameter bisa berupa objek kustom seperti Orang, Alamat, atau detail implementasi bisa lebih dari satu +. Tetapi logika pengujian akan sama.

Contoh Non-coding:

Asumsikan Anda sedang membangun mesin yang mengidentifikasi jenis dan merek perangkat elektronik untuk keamanan bandara. Mesin melakukan ini dengan memproses apa yang dilihatnya dengan kameranya.

Sekarang manajer Anda berjalan di pintu dan meminta Anda untuk mengujinya.

Maka Anda sebagai pengembang Anda dapat membawa 1000 objek nyata, seperti MacBook pro, Google Nexus, pisang, iPad dll di depannya dan uji dan lihat apakah semuanya bekerja.

Tetapi Anda juga dapat menggunakan benda - benda yang diejek , seperti MacBook pro yang identik (tanpa bagian internal yang nyata) atau pisang plastik di depannya. Anda dapat menyelamatkan diri dari investasi dalam 1000 laptop nyata dan pisang busuk.

Intinya adalah Anda tidak mencoba menguji apakah pisang itu palsu atau tidak. Juga tidak menguji apakah laptop itu palsu atau tidak. Semua yang Anda lakukan adalah pengujian jika mesin Anda setelah melihat pisang itu akan mengatakan not an electronic devicedan untuk MacBook Pro itu akan berkata: Laptop, Apple. Untuk mesin, hasil deteksi harus sama untuk elektronik palsu / diejek dan elektronik nyata

Logika yang disebutkan di atas berlaku untuk pengujian unit kode aktual juga. Itu adalah fungsi yang harus bekerja sama dengan nilai nyata yang Anda dapatkan dari input nyata (dan interaksi) atau diejeknilai yang Anda berikan selama pengujian unit. Dan sama seperti bagaimana Anda menyelamatkan diri dari menggunakan pisang nyata atau MacBook, dengan unit-test (dan mengejek) Anda menyelamatkan diri dari keharusan melakukan sesuatu yang menyebabkan server Anda mengembalikan kode status 500, 403, 200, dll. (Memaksa server Anda untuk memicu 500 hanya ketika server turun, sedangkan 200 adalah ketika server naik. Semakin sulit untuk menjalankan 100 tes fokus jaringan jika Anda harus terus-menerus menunggu 10 detik antara beralih dari server ke atas dan ke bawah). Jadi alih-alih Anda menyuntikkan / mengejek respons dengan kode status 500, 200, 403, dll dan menguji unit / fungsi Anda dengan nilai yang disuntikkan / diejek.

Contoh Pengodean:

Katakanlah Anda sedang menulis aplikasi iOS dan memiliki panggilan jaringan. Tugas Anda adalah menguji aplikasi Anda . Untuk menguji / mengidentifikasi apakah panggilan jaringan berfungsi seperti yang diharapkan BUKAN TANGGUNG JAWAB ANDA. Adalah tanggung jawab (tim server) pihak lain untuk mengujinya. Anda harus menghapus ketergantungan (jaringan) ini dan masih terus menguji semua kode Anda yang berfungsi di sekitarnya.

Panggilan jaringan dapat mengembalikan kode status berbeda 404, 500, 200, 303, dll dengan respons JSON.

Aplikasi Anda seharusnya berfungsi untuk semuanya (jika terjadi kesalahan, aplikasi Anda harus membuang kesalahan yang diharapkan). Apa yang Anda lakukan dengan mengejek adalah Anda membuat respons jaringan 'imajiner — mirip dengan respons nyata' (seperti 200 kode dengan file JSON) dan menguji kode Anda tanpa 'membuat panggilan jaringan nyata dan menunggu respons jaringan Anda'. Anda secara manual mengubah kode / mengembalikan respons jaringan untuk SEMUA jenis respons jaringan dan melihat apakah aplikasi Anda berfungsi seperti yang Anda harapkan. (Anda tidak pernah berasumsi / menguji 200 dengan data yang salah, karena itu bukan tanggung jawab Anda, tanggung jawab Anda adalah menguji aplikasi Anda dengan 200 yang benar, atau dalam kasus 400, 500, Anda menguji apakah aplikasi Anda melakukan kesalahan yang tepat)

Imajinasi yang menciptakan ini - mirip dengan yang nyata dikenal sebagai mengejek.

Untuk melakukan ini, Anda tidak dapat menggunakan kode asli Anda (kode asli Anda tidak memiliki tanggapan yang dimasukkan sebelumnya, kan?). Anda harus menambahkan sesuatu ke dalamnya, menyuntikkan / memasukkan data tiruan yang biasanya tidak diperlukan (atau bagian dari kelas Anda).

Jadi, Anda membuat instance kelas asli dan menambahkan apa pun (di sini adalah HTTPResponse jaringan, data ATAU dalam hal kegagalan, Anda melewati errorString yang benar, HTTPResponse) yang Anda butuhkan untuk itu dan kemudian menguji kelas yang diejek .

Singkatnya, mengejek adalah untuk menyederhanakan dan membatasi apa yang Anda uji dan juga membuat Anda memberi makan apa yang bergantung pada kelas. Dalam contoh ini Anda menghindari pengujian yang jaringan menyebut diri mereka sendiri , dan bukan uji apakah aplikasi Anda bekerja seperti yang Anda harapkan dengan disuntikkan output / tanggapan - oleh mengejek kelas

Tidak perlu dikatakan, Anda menguji setiap respons jaringan secara terpisah.


Sekarang pertanyaan yang selalu saya pikirkan adalah: Kontrak / titik akhir dan pada dasarnya respon JSON dari API saya diperbarui secara konstan. Bagaimana saya bisa menulis unit test yang mempertimbangkan ini?

Untuk menguraikan lebih lanjut tentang ini: katakanlah model membutuhkan kunci / bidang bernama username. Anda menguji ini dan tes Anda lulus. 2 minggu kemudian backend mengubah nama kunci menjadi id. Tes Anda masih berlalu. Baik? atau tidak?

Apakah itu tanggung jawab pengembang backend untuk memperbarui ejekan. Haruskah itu menjadi bagian dari perjanjian kami bahwa mereka memberikan cemoohan yang diperbarui?

Jawaban untuk masalah di atas adalah bahwa: unit test + proses pengembangan Anda sebagai pengembang sisi klien harus / akan menangkap respons yang sudah ketinggalan zaman. Jika Anda bertanya kepada saya bagaimana caranya? baik jawabannya adalah:

Aplikasi kami yang sebenarnya akan gagal (atau tidak gagal namun tidak memiliki perilaku yang diinginkan) tanpa menggunakan API yang diperbarui ... maka jika itu gagal ... kami akan membuat perubahan pada kode pengembangan kami. Yang lagi-lagi menyebabkan pengujian kami gagal .... yang harus kami perbaiki. (Sebenarnya jika kita ingin melakukan proses TDD dengan benar kita tidak boleh menulis kode apa pun tentang bidang kecuali kita menulis tes untuk itu ... dan melihatnya gagal dan kemudian pergi dan tulis kode pengembangan yang sebenarnya untuk itu.)

Ini semua berarti bahwa backend tidak harus mengatakan: "hei kita perbarui tiruan" ... itu akhirnya terjadi melalui pengembangan kode / debugging Anda. ‌ّ Karena itu semua adalah bagian dari proses pengembangan! Meskipun jika backend memberikan respons yang mengejek untuk Anda maka itu lebih mudah.

Seluruh poin saya dalam hal ini adalah bahwa (jika Anda tidak dapat secara otomatis mendapatkan tanggapan API yang diolok-olok yang diperbarui) beberapa interaksi manusia diperlukan, yaitu pembaruan JSON secara manual dan mengadakan pertemuan singkat untuk memastikan nilainya diperbarui akan menjadi bagian dari proses Anda

Bagian ini ditulis berkat diskusi kendur dalam kelompok pertemuan CocoaHead kami


Hanya untuk iOS devs:

Contoh yang sangat baik dari mengejek adalah pembicaraan Praktis-Berorientasi Protokol oleh Natasha Muraschev . Langsung saja ke menit 18:30, meskipun slide mungkin tidak sinkron dengan video yang sebenarnya 🤷‍♂️

Saya sangat suka bagian ini dari transkrip:

Karena ini adalah pengujian ... kami ingin memastikan bahwa getfungsi dari Gettabledipanggil, karena dapat kembali dan fungsinya secara teoritis dapat menetapkan berbagai item makanan dari mana saja . Kita perlu memastikan bahwa itu disebut;

Madu
sumber
3
Contoh yang bagus, saya hanya akan menambahkan bahwa dalam contoh khusus ini, subclass bertindak sebagai tiruan, tetapi contoh ini juga menggunakan stubbing. Respons JSON yang dikodekan dengan keras dianggap sebagai respons yang tidak dapat dilakukan. Saya hanya menambahkan ini karena sulit untuk membedakan antara tiruan dan bertopik, tetapi contoh ini jelas menunjukkan bagaimana keduanya dapat digunakan bersama.
user3344977
Penjelasan yang bagus, terima kasih. Satu tweak kecil untuk pertanyaan tentang perubahan API. Bagaimana jika itu bukan API Anda sehingga Anda bukan bagian dari proses pengembangan? Saya ingin tahu kapan perpustakaan klien saya gagal.
ThinkDigital
@ThinkDigital Penyedia API yang baik memiliki catatan rilis yang baik dan mengkomunikasikan perubahan dengan benar, jika Anda tidak memiliki saluran itu maka mungkin saatnya bagi Anda untuk duduk dalam rapat dan membahasnya | pengembang yang baik akan selalu melihat perubahan API dari versi baru dan menghindari hanya meningkatkan versi API. Apakah Anda memiliki versi API? Jika tidak satu pun dari mereka yang menangkapnya maka pada QAing Anda akan mengetahuinya, kemudian perbarui tugas tes Anda dari seluruh tim. → tugas seorang pengembang tunggal: seharusnya tidak terlalu peduli. Hanya menangani kasus di mana server mengembalikan kesalahan, atau server tidak mengembalikan kesalahan tetapi tidak dapat mengurai json, atau menangani kasus yang benar.
Sayang
Terima kasih telah merespons, @Sayang! Dalam kasus saya, saya mempertahankan klien untuk pub.dev , yang memiliki API, tetapi sangat kurang. Sedemikian rupa sehingga lebih baik membuat API dengan mengikis situs mereka, daripada menggunakan API resmi mereka. Karena itu, perubahan pada situs dapat memecahkan kode dan mereka tidak perlu repot memperbarui siapa pun dalam kasus ini. Situs ini open source, tetapi berbeda mempertahankan API yang didasarkan pada perubahan yang dibuat berdasarkan hal yang lebih sepele.
ThinkDigital
32

Ada banyak jawaban di SO dan posting bagus di web tentang mengejek. Satu tempat yang Anda mungkin ingin mulai mencari adalah posting oleh Martin Fowler Mocks Aron't Stubs di mana ia membahas banyak ide mengejek.

Dalam satu paragraf - Mengejek adalah salah satu teknik partikel untuk memungkinkan pengujian unit kode tanpa bergantung pada dependensi. Secara umum, apa yang membedakan mengejek dari metode lain adalah bahwa objek tiruan yang digunakan untuk menggantikan dependensi kode akan memungkinkan ekspektasi ditetapkan - objek tiruan akan tahu bagaimana itu dimaksudkan untuk dipanggil oleh kode Anda dan bagaimana merespons.


Pertanyaan awal Anda menyebutkan TypeMock, jadi saya tinggalkan jawaban saya di bawah ini:

TypeMock adalah nama kerangka kerja mengejek komersial .

Ini menawarkan semua fitur kerangka mengejek gratis seperti RhinoMocks dan Moq, ditambah beberapa opsi yang lebih kuat.

Apakah Anda membutuhkan TypeMock atau tidak, sangat bisa diperdebatkan - Anda dapat melakukan sebagian besar mengejek yang Anda inginkan dengan pustaka ejekan gratis, dan banyak yang berpendapat bahwa kemampuan yang ditawarkan oleh TypeMock akan sering membuat Anda menjauh dari desain yang dienkapsulasi dengan baik.

Sebagai jawaban lain yang dinyatakan 'TypeMocking' sebenarnya bukan konsep yang didefinisikan, tetapi dapat dianggap sebagai jenis mengejek yang menawarkan TypeMock, menggunakan profiler CLR untuk mencegat panggilan .Net saat runtime, memberikan kemampuan yang jauh lebih besar untuk objek palsu (bukan persyaratan seperti membutuhkan antarmuka atau metode virtual).

David Hall
sumber
@Masoud tidak pernah menyebut TypeMock. Pertanyaannya adalah tentang "tipe mengejek" secara umum.
Peter Lillevold
4
@ Peter - seperti komentar lain, periksa riwayat edit pertanyaan. Tidak banyak yang bisa saya lakukan jika saya mengirim jawaban dan kemudian pertanyaan awal benar-benar berubah.
David Hall
9

Mock adalah metode / objek yang mensimulasikan perilaku metode / objek nyata dengan cara yang terkontrol. Objek tiruan digunakan dalam pengujian unit.

Seringkali metode yang sedang diuji memanggil layanan eksternal lain atau metode di dalamnya. Ini disebut dependensi. Setelah diejek, dependensi berperilaku seperti yang kita definisikan.

Dengan dependensi yang dikendalikan oleh mock, kita dapat dengan mudah menguji perilaku metode yang kita kodekan. Ini adalah Unit testing.

Apa tujuan dari benda tiruan?

Mengejek vs bertopik

Tes unit vs Tes fungsional

Venkat Kotra
sumber
7

Mengejek adalah menghasilkan objek semu yang mensimulasikan perilaku objek nyata untuk pengujian

LOL
sumber
5

Tujuan dari tipe mengejek adalah untuk memutuskan dependensi untuk mengisolasi tes ke unit tertentu. Rintisan bertopik pengganti sederhana, sedangkan mengejek adalah pengganti yang dapat memverifikasi penggunaan. Kerangka kerja mengejek adalah alat yang akan membantu Anda menghasilkan bertopik dan mengejek.

EDIT : Karena kata-kata aslinya menyebutkan "mengejek" saya mendapat kesan bahwa ini terkait dengan TypeMock. Dalam pengalaman saya, istilah umum hanya "mengejek". Silakan mengabaikan info di bawah ini secara khusus tentang TypeMock.

TypeMock Isolator berbeda dari kebanyakan kerangka kerja mengejek lainnya karena ia berfungsi memodifikasi IL saya dengan cepat. Itu memungkinkannya untuk mengejek tipe dan instance yang tidak bisa diejek oleh kerangka kerja lain. Untuk mengejek jenis / instance ini dengan kerangka kerja lain Anda harus memberikan abstraksi Anda sendiri dan mengejek ini.

TypeMock menawarkan fleksibilitas tinggi dengan mengorbankan lingkungan runtime yang bersih. Sebagai efek samping dari cara TypeMock mencapai hasilnya, terkadang Anda akan mendapatkan hasil yang sangat aneh saat menggunakan TypeMock.

Brian Rasmussen
sumber
@Masoud tidak pernah menyebut TypeMock. Pertanyaannya adalah tentang "tipe mengejek" secara umum.
Peter Lillevold
1
@ Peter: Kata-kata aslinya adalah "apa tipe mengejek?"
Brian Rasmussen
Aku tahu. Karena "tipe mengejek" tidak sama dengan "TypeMock", saya menemukan jawaban Anda dan @Oded cukup melenceng.
Peter Lillevold
1
@ Peter: Dalam pengalaman saya, istilah umumnya adalah "mengejek", tetapi bagaimanapun saya telah memperbarui jawaban saya untuk mudah-mudahan menjelaskan. Terima kasih atas masukannya.
Brian Rasmussen
3

Saya akan berpikir penggunaan kerangka kerja mock isolator TypeMock akan menjadi TypeMocking.

Ini adalah alat yang menghasilkan tiruan untuk digunakan dalam unit test, tanpa perlu menulis kode Anda dengan IoC.

Oded
sumber
@Masoud tidak pernah menyebut TypeMock. Pertanyaannya adalah tentang "tipe mengejek" secara umum.
Peter Lillevold
3
Sebenarnya, pertanyaan awal termasuk kata "Ketik" sebelum "Mengejek", tetapi kemudian diedit. Itulah sebabnya beberapa jawaban berisi informasi spesifik tentang TypeMock.
Martin Liversage
1

Jika tiruan Anda melibatkan permintaan jaringan, alternatif lain adalah memiliki server uji sungguhan untuk dipukul. Anda dapat menggunakan layanan ini untuk menghasilkan permintaan dan tanggapan untuk pengujian Anda. http://testerurl.com/

foobar8675
sumber
Saya baru saja mencoba mengaksesnya, dan butuh beberapa menit. Siapa bilang itu tidak secara diam-diam mencatat permintaan juga? Akhirnya, ini mungkin lebih baik sebagai komentar :)
Kieren Johnstone
Saya benar-benar mengambilnya karena saya tidak ingin memindahkannya ke hosting gratis. ya, ini seharusnya komentar. itu adalah open source, jadi jika ada kekhawatiran tentang permintaan logging, Anda bisa menjalankannya sendiri. github.com/captainchung/TesterUrl
Matthew Chung