Bir sınıfla alay etmek: Mock () veya patch ()?


116

Python ile alay kullanıyorum ve bu iki yaklaşımdan hangisinin daha iyi olduğunu merak ediyordum (okuyun: daha pitonik).

Birinci yöntem : Sadece sahte bir nesne oluşturun ve bunu kullanın. Kod şöyle görünür:

def test_one (self):
    mock = Mock()
    mock.method.return_value = True 
    self.sut.something(mock) # This should called mock.method and checks the result. 
    self.assertTrue(mock.method.called)

İkinci yöntem : Sahte oluşturmak için yamayı kullanın. Kod şöyle görünür:

@patch("MyClass")
def test_two (self, mock):
    instance = mock.return_value
    instance.method.return_value = True
    self.sut.something(instance) # This should called mock.method and checks the result. 
    self.assertTrue(instance.method.called)

Her iki yöntem de aynı şeyi yapar. Farklılıklardan emin değilim.

Biri beni aydınlatabilir mi?


10
Mock () ya da yamayı hiç denememiş biri olarak, ilk sürümün daha net olduğunu ve gerçek farkı anlamamama rağmen ne yapmak istediğinizi gösterdiğini hissediyorum. Bunun herhangi bir yardımı olup olmadığını bilmiyorum, ancak başlatılmamış bir programcının neler hissedebileceğini aktarmanın yararlı olabileceğini düşündüm.
Michael Brennan

2
@MichaelBrennan: Yorumunuz için teşekkürler. Gerçekten faydalıdır.
Sardathrion - SE istismarına karşı

Yanıtlar:


151

mock.patchbundan çok çok farklı bir yaratıktır mock.Mock. patch yerini sahte bir nesne ile sınıf ve sahte örneği çalışabilmesini sağlar. Şu pasaja bir göz atın:

>>> class MyClass(object):
...   def __init__(self):
...     print 'Created MyClass@{0}'.format(id(self))
... 
>>> def create_instance():
...   return MyClass()
... 
>>> x = create_instance()
Created MyClass@4299548304
>>> 
>>> @mock.patch('__main__.MyClass')
... def create_instance2(MyClass):
...   MyClass.return_value = 'foo'
...   return create_instance()
... 
>>> i = create_instance2()
>>> i
'foo'
>>> def create_instance():
...   print MyClass
...   return MyClass()
...
>>> create_instance2()
<mock.Mock object at 0x100505d90>
'foo'
>>> create_instance()
<class '__main__.MyClass'>
Created MyClass@4300234128
<__main__.MyClass object at 0x100505d90>

patchMyClass, aradığınız işlevlerde sınıfın kullanımını kontrol etmenize olanak tanıyan bir şekilde değiştirir . Bir sınıfa yama uyguladığınızda, sınıfa yapılan referanslar tamamen sahte örnekle değiştirilir.

mock.patchgenellikle testin içinde bir sınıfın yeni bir örneğini oluşturan bir şeyi test ederken kullanılır. mock.Mockörnekler daha nettir ve tercih edilir. Senin Eğer self.sut.somethingyöntem bir örneğini oluşturdu MyClassyerine bir parametre olarak bir örneğini aldıktan sonra mock.patchburada uygun olacaktır.


2
@ D.Shawley, test edilmesi gereken başka bir sınıf içinde örneklenen bir sınıfa nasıl yama yaparız?
ravi404

4
@ravz - "Where to Patch" bölümünü okuyun. Bu, düzgün çalışması için en zor şeylerden biridir.
D.Shawley

Sahte testim İkinci Yönteme benzer . MyClass örneğinin bir istisna oluşturmasını istiyorum. Hem mock.side_effect hem de mock.return_value.side_effect'i denedim ve bunlar işe yaramadı. Ben ne yaparım?
Hussain

5
@ D.Shawley Bağlantı koptu, şimdi burada bulunabilir: "Nereye Yama
Yapılır

2
Bir sınıf nesnesine yama yapmak için stackoverflow.com/questions/8469680/… '
ye

27

Bununla ilgili bir YouTube videom var .

Kısa cevap: mockAlay edilmek istediğiniz şeyi geçerken ve değilseniz kullanın patch. İkisi arasında, uygun bağımlılık enjeksiyonu ile kod yazdığınız anlamına geldiği için alay şiddetle tercih edilir.

Aptalca örnek:

# Use a mock to test this.
my_custom_tweeter(twitter_api, sentence):
    sentence.replace('cks','x')   # We're cool and hip.
    twitter_api.send(sentence)

# Use a patch to mock out twitter_api. You have to patch the Twitter() module/class 
# and have it return a mock. Much uglier, but sometimes necessary.
my_badly_written_tweeter(sentence):
    twitter_api = Twitter(user="XXX", password="YYY")
    sentence.replace('cks','x') 
    twitter_api.send(sentence)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.