Mock vs MagicMock

144

Pemahaman saya adalah bahwa MagicMock adalah superset dari Mock yang secara otomatis melakukan "metode ajaib" sehingga secara mulus memberikan dukungan untuk daftar, iterasi, dan sebagainya ... Lalu apa alasan keberadaan Mock biasa ? Bukankah itu hanya versi MagicMock yang dipreteli yang secara praktis dapat diabaikan? Apakah kelas Mock mengetahui trik yang tidak tersedia di MagicMock ?

Vladimir Ignatov
sumber

Jawaban:

101

Apa alasan keberadaan Mock biasa ?

Penulis Mock, Michael Foord, menjawab pertanyaan yang sangat mirip di Pycon 2011 (31:00) :

T: Mengapa MagicMock membuat hal yang terpisah daripada hanya melipat kemampuan menjadi objek tiruan default?

J: Satu jawaban yang masuk akal adalah cara kerja MagicMock adalah ia mengkonfigurasi semua metode protokol ini dengan membuat Mock baru dan menyetelnya, jadi jika setiap tiruan baru membuat sekumpulan tiruan baru dan menetapkannya sebagai metode protokol dan kemudian semua protokol tersebut metode membuat lebih banyak tiruan dan mengaturnya pada metode protokol mereka, Anda punya rekursi tak terbatas ...

Bagaimana jika Anda ingin mengakses tiruan Anda sebagai objek kontainer menjadi kesalahan - Anda tidak ingin itu berfungsi? Jika setiap tiruan secara otomatis mendapatkan setiap metode protokol, maka itu menjadi jauh lebih sulit untuk melakukannya. Dan juga, MagicMock melakukan beberapa prakonfigurasi ini untuk Anda, menetapkan nilai kembalian yang mungkin tidak sesuai, jadi saya pikir akan lebih baik untuk memiliki kemudahan ini yang memiliki segalanya yang telah dikonfigurasi sebelumnya dan tersedia untuk Anda, tetapi Anda juga dapat mengambil tiruan biasa objek dan cukup konfigurasikan metode ajaib yang Anda inginkan ...

Jawaban sederhananya adalah: gunakan saja MagicMock di mana saja jika itu perilaku yang Anda inginkan.

Ryne Everett
sumber
14
Saya pikir jawaban yang lebih baik adalah: Gunakan MagicMock jika Anda tahu apa yang Anda lakukan, jika tidak gunakan Mock.
laike9m
@ laike9m Saya membaca saran itu sebagai sebaliknya: gunakan saja MagicMock, kecuali Anda tahu apa yang Anda lakukan dan menginginkan perilaku tertentu, dalam hal ini mulailah dengan Mock dan gulung sendiri.
Robino
@Robino kurasa tidak. Komentar di bawah jawaban Sean Redmond menjelaskannya dengan baik.
laike9m
Dokumen resmi merekomendasikan sebaliknya, "Karena MagicMock adalah kelas yang lebih mampu, ia membuatnya masuk akal untuk digunakan secara default." docs.python.org/dev/library/…
Robino
58

Dengan Mock Anda dapat mengejek metode sulap tetapi Anda harus menentukannya. MagicMock memiliki "implementasi default dari sebagian besar metode ajaib." .

Jika Anda tidak perlu menguji metode sulap apa pun, Mock sudah memadai dan tidak membawa banyak hal asing ke dalam pengujian Anda. Jika Anda perlu menguji banyak metode ajaib, MagicMock akan menghemat waktu Anda.

Sean Redmond
sumber
Benar saja saya sudah membaca dokumentasinya. Itu tidak menjawab pertanyaan saya - mengapa repot-repot dengan Mock biasa jika MagicMock melakukan hal yang sama dan lebih banyak lagi? Saya tidak melihat hal-hal asing dalam pengujian saya - cukup gunakan nama yang berbeda dan hanya itu. Jadi dimana tangkapannya?
Vladimir Ignatov
39
Pengujian harus minimal dan objek tiruan harus berfungsi minimal sehingga Anda yakin dengan apa yang Anda uji. Jika Anda menggunakan MagicMock hanya karena is tidak lebih tetapi Anda tidak secara eksplisit menguji semua itu "lebih" Anda menjalankan risiko pengujian gagal karena perilaku MagicMock default. Kegagalan ini mungkin mencerminkan sesuatu tentang default MagicMock lebih dari hal yang seharusnya diejek. Lebih buruk lagi, Anda menjalankan risiko pengujian berhasil padahal seharusnya gagal. Risikonya kecil tapi jika ini terjadi maka akan membuang banyak waktu anda.
Sean Redmond
1
Saya menganggapnya seperti menggunakan JS biasa vs Jquery. Tentu, Anda dapat menggunakan Jquery untuk melakukan semua JS Anda, tetapi dalam beberapa kasus, Anda hanya ingin menggunakan alat yang sangat minimum yang diperlukan untuk menyelesaikan pekerjaan. Saya menemukan kasus-kasus itu biasanya sangat sederhana atau sangat kompleks.
merapat
54

Pertama-tama, MagicMockadalah subkelas dari Mock.

class MagicMock(MagicMixin, Mock)

Hasilnya, MagicMock menyediakan semua yang disediakan Mock dan banyak lagi. Daripada memikirkan Mock sebagai versi MagicMock yang dipreteli, pikirkan MagicMock sebagai versi tambahan dari Mock. Ini harus menjawab pertanyaan Anda tentang mengapa Mock ada dan apa yang disediakan Mock di atas MagicMock.

Kedua, MagicMock menyediakan implementasi default dari banyak / sebagian besar metode sulap, sedangkan Mock tidak. Lihat di sini untuk informasi lebih lanjut tentang metode ajaib yang disediakan.

Beberapa contoh metode sulap yang disediakan:

>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0

Dan ini yang mungkin tidak intuitif (setidaknya tidak intuitif bagi saya):

>>> with MagicMock():
...     print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>

Anda dapat "melihat" metode yang ditambahkan ke MagicMock saat metode tersebut dipanggil untuk pertama kalinya:

>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]

Jadi, mengapa tidak menggunakan MagicMock setiap saat?

Pertanyaan kembali kepada Anda adalah: Apakah Anda setuju dengan penerapan metode ajaib default? Misalnya, apakah boleh untuk mocked_object[1]tidak melakukan kesalahan? Apakah Anda baik-baik saja dengan konsekuensi yang tidak diinginkan karena penerapan metode sihir sudah ada?

Jika jawaban atas pertanyaan ini adalah ya, lanjutkan dan gunakan MagicMock. Jika tidak, tetap gunakan Mock.

pengguna650654
sumber
13

Inilah yang dikatakan oleh dokumentasi resmi python :

Dalam sebagian besar contoh ini, kelas Mock dan MagicMock dapat dipertukarkan. Karena MagicMock adalah kelas yang lebih mampu, maka MagicMock adalah kelas yang masuk akal untuk digunakan secara default.

pengguna2916464
sumber
3

Saya telah menemukan kasus khusus lain di mana sederhana Mock mungkin berubah lebih berguna daripada MagicMock:

In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False

Membandingkan ANYdapat bermanfaat, misalnya, membandingkan hampir setiap kunci antara dua kamus tempat beberapa nilai dihitung menggunakan tiruan.

Ini akan valid jika Anda menggunakan Mock:


self.assertDictEqual(my_dict, {
  'hello': 'world',
  'another': ANY
})

sementara itu akan memunculkan AssertionErrorjika Anda pernah menggunakannyaMagicMock

Manu
sumber