クラスのモック:Mock()またはpatch()?


116

私はPythonでモックを使用しており、これらの2つのアプローチのどちらが優れているのか疑問に思っていました(読んで:よりpythonic)。

方法1:模擬オブジェクトを作成して使用するだけです。コードは次のようになります。

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)

方法2:patchを使用してモックを作成します。コードは次のようになります。

@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)

どちらの方法も同じことを行います。違いがわかりません。

誰かが私を啓発できますか?


10
Mock()とパッチのどちらも試したことがない人なので、実際の違いはわかりませんが、最初のバージョンの方がわかりやすく、やりたいことを示しています。これが助けになるかどうかはわかりませんが、初心者のプログラマーが何を感じているかを伝えるのに役立つと思いました。
Michael Brennan

2
@MichaelBrennan:コメントありがとうございます。さすがに便利です。
サルダトリオン-

回答:


151

mock.patchとは非常に非常に異なる生き物ですmock.Mock。 クラスをモックオブジェクトにpatch 置き換え、モックインスタンスを操作できるようにします。このスニペットを見てください:

>>> 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呼び出す関数でのクラスの使用を制御できるように置き換えます。クラスにパッチを適用すると、クラスへの参照は完全にモックインスタンスに置き換えられます。

mock.patch通常、テスト内でクラスの新しいインスタンスを作成するものをテストするときに使用されます。 mock.Mockインスタンスはより明確であり、推奨されます。あなたの場合はself.sut.somethingこの方法でのインスタンス作成したMyClass代わりに、パラメータとしてインスタンスを受け取るのを、その後、mock.patchここで適切であろう。


2
@ D.Shawleyテストする必要がある別のクラス内でインスタンス化されたクラスにパッチを適用する方法。
ravi404 2013

4
@ravz- 「パッチの適用先」に読み取り与えます。これは、適切に動作させるために最も困難なことの1つです。
D.Shawley 2013年

私の模擬テストは方法2に似ています。MyClassインスタンスで例外を発生させたい。私はmock.side_effectとmock.return_value.side_effectの両方を試しましたが、うまくいきませんでした。私は何をしますか?
フセイン

5
@ D.Shawleyリンクが壊れています。ここで見つけることができます:「パッチの場所」
RazerM

2
クラスオブジェクトにパッチを適用するには、stackoverflow.com
questions / 8469680 /…を

27

私が持っているYouTubeの動画をこれに。

短い答え:mockあざけりたいものを渡すとき、そうでないときに使用しますpatch。2つのうち、適切な依存関係注入を使用してコードを記述していることを意味するため、モックが強く推奨されます。

愚かな例:

# 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)
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.