Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python2.7模拟类的void方法_Python_Python 2.7_Unit Testing - Fatal编程技术网

Python2.7模拟类的void方法

Python2.7模拟类的void方法,python,python-2.7,unit-testing,Python,Python 2.7,Unit Testing,我试图使用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): ... #

我试图使用
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) -> ()
        ...
在我的测试代码中,我试图模拟对
start()
的调用,如下所述

BaseUpgradeHandler
对象由
get\u upgrade\u handler()的
ServiceRegistry
方法返回。当我在测试中执行上述代码时,我看到仍在调用
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()
有人能告诉我如何模拟对
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()

有人能解释一下为什么我还需要修补ServiceRegistry吗?

您提供的代码不足以看到导致问题的部分。我们需要查看模块
serviceregistry
,以确定这一点,但我会进行一个有根据的猜测:

您有一个文件
a.py
(也称为
baseupgradehandler
),如下所示:

class A:
    def method(self):
        print("It's real!")
from a import A

class B:
    def get_A(self):
        return A()
还有一个文件
b.py
(又称
serviceregistry
),如下所示:

class A:
    def method(self):
        print("It's real!")
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
模块中的引用,但是
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 = ''
    
  • 避免在打补丁之前导入模块(可能不可行或是个好主意):


我使用unittest.mock已经有一段时间了,有时我还会重新发明轮子。我决定让mockito成为我项目的一部分,现在事情看起来好多了。任何类型的模拟验证都非常简单,如果可以的话,我坚决鼓励您将mockito作为库的一部分。这个库有一个很好的文档,到目前为止,它比unittest.mock IMHO更容易。

patch
用作上下文管理器,只在
块中使用
对方法进行修补。你可能在外面叫它。如果您想为整个测试方法修补该方法,请使用
patch
作为装饰器。另外:如果您想
将('mcommon.baseupgradehandler.baseupgradehandler.start')修补为方法:method.return\u value='
@Bakuriu-不,我不是在外部调用它,那么您可以只模拟该方法。我已经编辑了这个问题。我不想修补整个测试方法。因此,我将
一起使用。如果我按照你的建议,将
补丁('mcommon.baseupgradehandler.baseupgradehandler.start')作为方法:method.return_value='
,那么这是可以预期的。我在
BaseUpgradeHandler
中有多种方法可以模拟。那么,我必须像你建议的那样模仿每一种方法吗?或者还有其他方法吗?我无法重现你的问题。您如何检查是否调用了真正的方法?我们需要一个完整的例子来重现这个问题,以理解为什么补丁在您的案例中不起作用。可能您是通过修补之前获取的引用访问该类。如果你把
patch
放在装饰者的位置,这种行为还会发生吗?@Bakuriu-我已经编辑了我的问题。它是更大代码库的一部分。我将尝试有一个完整的玩具的例子。但是,如果上面的编辑提供了任何线索,一定要告诉我。只是一个提示:你来自一个庞大的代码库并不重要。首先“注释掉”该测试未使用的所有代码。然后注释掉该测试未直接使用的所有类/函数/方法。然后将查找文件/数据库的函数的实现更改为只返回固定结果。现在,不管您来自哪里,您应该拥有很少的类,其中几乎没有实现。看看问题是否仍然存在。如果没有,请尝试添加更多代码并重复。大多数时候,通过这个过程,你会找到答案。