Python Mock Patch 一个类中的多个方法

新手上路,请多包涵

我试图修补一个类中的多个方法。这是我的简化设置

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

直觉上,第二个似乎也应该有效,但事实并非如此。能不能帮忙解释下为什么不行。我怀疑它与 “在哪里打补丁” 有关,但我无法弄清楚。

原文由 kvb 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

经过一些测试后,我找到了问题所在。

在第二个测试用例中,补丁装饰器创建了一个 Mock 类的新实例,并通过 mock_hook 参数将其传递给 test_execute2 函数。让我们将其称为 mock1。 mock1 替换了 HookTransfer.py 中的 Hook 类。当运行 self.hook = Hook() 时,它转换为调用模拟1的 __init__ 。按照设计,这会返回另一个 Mock 实例——让我们将其称为 mock2。所以 self.hook 指向 mock2。但是 mock_hook.get_key = mock.Mock(return_value="New_Key") 了 mock1 中的方法。

为了正确模拟,mock2 需要打补丁。这可以通过两种方式完成

  1. 通过模拟 mock1 的 return_value(返回 mock2) mock_hook.return_value.get_key = mock.Mock(return_value="New_Key")
  2. 模拟 mock1 构造函数的返回值(返回 mock2) mock_hook().get_key = mock.Mock(return_value="New_Key")

在包装下,这两个选项实际上做同样的事情。

原文由 kvb 发布,翻译遵循 CC BY-SA 3.0 许可协议

您可以使用 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() 用作装饰器时,将模拟通过关键字传递到装饰函数中,并在用作上下文管理器时返回字典。

原文由 Eugene Yarmash 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题