我试图在一个类中修补多个方法。这是我简化的设置
Hook.py定义为
class Hook():
def get_key(self):
return "Key"
def get_value(self):
return "Value"
HookTransfer.py定义为
from Hook import Hook
class HookTransfer():
def execute(self):
self.hook = Hook()
key = self.hook.get_key()
value = self.hook.get_value()
print(key)
print(value)
我想在Hook类中模拟get_key和get_value方法。以下作品即打印New_Key和New_Value
from HookTransfer import HookTransfer
import unittest
from unittest import mock
class TestMock(unittest.TestCase):
@mock.patch('HookTransfer.Hook.get_key', return_value="New_Key")
@mock.patch('HookTransfer.Hook.get_value', return_value="New_Value")
def test_execute1(self, mock_get_key, mock_get_value):
HookTransfer().execute()
if __name__ == '__main__':
unittest.main()
但事实并非如此。它会打印<MagicMock name='Hook().get_key()' id='4317706896'>
和<MagicMock name='Hook().get_value()' id='4317826128'>
from HookTransfer import HookTransfer
import unittest
from unittest import mock
class TestMock(unittest.TestCase):
@mock.patch('HookTransfer.Hook', spec=True)
def test_execute2(self, mock_hook):
mock_hook.get_key = mock.Mock(return_value="New_Key")
mock_hook.get_value = mock.Mock(return_value="New_Value")
HookTransfer().execute()
if __name__ == '__main__':
unittest.main()
直观地看起来第二个也应该起作用,但它没有。你能帮忙解释一下为什么没有。我怀疑这与"where to patch"有关,但我无法明白。
答案 0 :(得分:4)
您需要的是:
模拟Hook类,
from HookTransfer import HookTransfer
from Hook import Hook
import unittest
try:
import mock
except ImportError:
from unittest import mock
class TestMock(unittest.TestCase):
@mock.patch.object(Hook, 'get_key', return_value="New_Key")
@mock.patch.object(Hook, 'get_value', return_value="New_Value")
def test_execute1(self, mock_get_key, mock_get_value):
HookTransfer().execute()
if __name__ == "__main__":
unittest.main()
答案 1 :(得分:4)
您可以使用patch.multiple()
修补模块或类的多个方法。这样的事情应该适合您的情况:
import unittest
from unittest.mock import MagicMock, patch
class TestMock(unittest.TestCase):
@patch.multiple('HookTransfer.Hook',
get_key=MagicMock(return_value='New_Key'),
get_value=MagicMock(return_value='New_Value'))
def test_execute1(self, **mocks):
HookTransfer().execute()
将patch.multiple()
用作修饰符时,模拟将通过关键字传递到修饰的函数中,并在用作上下文管理器时返回字典。
答案 2 :(得分:2)
经过一些测试后,我找到了问题。
在第二个测试用例中,补丁装饰器创建一个Mock类的新实例,并通过mock_hook参数将其传递给test_execute2函数。让我们将其称为mock1。 mock1替换了HookTransfer.py中的Hook类。运行self.hook = Hook()
时,它会转换为调用mock1的__init__
。通过设计,这将返回另一个Mock实例 - 让我们将其称为mock2。所以self.hook指向mock2。但是mock_hook.get_key = mock.Mock(return_value="New_Key")
,模拟了mock1中的方法。
为了正确模拟,需要修补mock2。这可以通过两种方式完成
mock_hook.return_value.get_key = mock.Mock(return_value="New_Key")
mock_hook().get_key = mock.Mock(return_value="New_Key")
在两个选项下,两个选项确实做同样的事情。