我正在尝试使用unittests.mock
模拟对象的void方法调用。
我的包裹如下所示
common
baseupgradehandler.py
baseupgradehandler.py
class BaseUpgradeHandler(object):
def __init__(self, upgrade_config, upgrade_state, system_config, pre_step, main_step, post_step):
...
# Method call to be supressed
def start(self, service_manifest, upgrade_bundle):
# type: (service_version_pb2.ServiceManifest, str) -> ()
...
在测试代码中,我尝试像documentation中所述,模拟对start()
的调用,如下所示。
from workflow.upgradeworkflow import UpgradeWorkflow
from common.serviceregistry import ServiceRegistry
# The above imports are at the start of the test file
...
with patch('common.baseupgradehandler.BaseUpgradeHandler') as handler_mock: # type: Mock
handler_mock.return_value.start.return_value = ''
wf = UpgradeWorkflow(ServiceRegistry(self.service_bundle, config, sys_config, state),
config,
state,
sys_config)
BaseUpgradeHandler
对象由get_upgrade_handler()
的{{1}}方法返回。在测试中执行上述代码时,我看到ServiceRegistry
仍在被调用。
有人可以让我知道如何模拟对BaseUpgradeHandler.start()
的调用,以便不调用该方法吗?
编辑
如果我按如下所示更改补丁代码,则它可以按预期工作,start()
被嘲笑,BaseUpgradeHandler
没有被调用。
start
有人可以向我解释为什么我也必须修补with patch('common.baseupgradehandler.BaseUpgradeHandler') as handler_mock: # type: Mock
handler_mock.return_value.start.return_value = ''
with patch('common.serviceregistry.ServiceRegistry') as serviceregistry_mock: # type: Mock
serviceregistry_mock.return_value.get_upgrade_handler.return_value = handler_mock
wf = UpgradeWorkflow(ServiceRegistry(self.service_bundle, config, sys_config, state), config, state, sys_config)
wf.start()
吗?
答案 0 :(得分:1)
您提供的代码不足以查看导致问题的部分。我们需要确保查看模块serviceregistry
,但我会做一个有根据的猜测:
您有一个文件a.py
(又名baseupgradehandler
),如下所示:
class A:
def method(self):
print("It's real!")
还有一个文件b.py
(又名serviceregistry
),如下所示:
from a import A
class B:
def get_A(self):
return A()
在测试文件中,您可以执行以下操作:
import unittest
from unittest.mock import patch
from b import B
from a import A
游戏结束!
B
模块现在已经引用了原始的A
类。 之后,您patch('a.A')
仅仅更改了a
模块中的引用,但是patch
无法知道B
有对原始A
的引用。
您可以通过三种方式解决此问题:
也修补b.A
:
with patch('a.A') as h_a, patch('b.A') as h_b:
h_a.return_value.method.return_value = ''
h_b.return_value.method.return_value = ''
在修补之前,避免导入模块(可能不可行或一个好主意):
import unittest
from unittest.mock import patch
class MyTest(unittest.TestCase):
def test_one(self):
with patch('a.A') as h:
h.return_value.method.return_value = ''
from b import B
B().get_A().method()
答案 1 :(得分:0)
一段时间以来,我一直在使用unittest.mocks,有时我又在重新发明轮子。我决定将Mockito纳入我的项目,现在情况看起来好多了。任何一种模拟验证都非常简单,如果可以的话,我绝对鼓励您将模拟成为您的库的一部分。该库有很好的文档,到目前为止,它比unittest.mock恕我直言要容易得多。