私はPythonで mock を使用しており、これらの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("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)
どちらの方法も同じことを行います。違いがわかりません。
誰でも私を啓発できますか?
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>
patch
は、MyClass
を置き換えて、呼び出す関数でクラスの使用を制御できるようにします。クラスにパッチを適用すると、クラスへの参照は完全にモックインスタンスに置き換えられます。
mock.patch
は通常、テスト内でクラスの新しいインスタンスを作成する何かをテストするときに使用されます。 mock.Mock
インスタンスはより明確で優先されます。 self.sut.something
メソッドがインスタンスをパラメーターとして受け取る代わりにMyClass
のインスタンスを作成した場合、ここではmock.patch
が適切です。
これについて 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)