在python中进行测试时,如何删除装饰器的效果?[重复]


问题内容

这个问题已经在这里有了答案

如何在python中模拟导入的pypi库使用的函数调用 (2个答案)

5年前关闭。

retry在python的某些代码中使用装饰器。但我想通过消除其影响来加快测试速度。

我的代码是:

@retry(subprocess.CalledProcessError, tries=5, delay=1, backoff=2, logger=logger)
def _sftp_command_with_retries(command, pem_path, user_at_host):
    # connect to sftp, blah blah blah
    pass

测试时如何去除装饰器的效果?我无法创建未经装饰的版本,因为我正在测试使用该版本的更高级别的功能。

由于retry使用time.sleep了后退功能,因此理想情况下我可以打补丁,time.sleep但是由于这是在装饰器中进行的,因此我认为这是不可能的。

有什么方法可以加快使用此功能的测试代码的速度吗?

更新资料

我基本上是在尝试测试使用此功能的高层函数,以确保它们捕获到抛出的任何异常_sftp_command_with_retries。由于retry装饰器将传播它们,因此我需要一个更复杂的模拟。

因此,从这里我可以看到如何模拟装饰器。但是现在我需要知道如何编写本身就是装饰器的模拟程序。它需要调用_sftp_command_with_retries,如果引发异常,则将其传播,否则返回返回值。

导入我的函数后添加此功能不起作用:

_sftp_command_with_retries = _sftp_command_with_retries.__wrapped__

问题答案:

retry您使用的装饰是建立在顶部decorator.decorator实用的装饰,如果未安装包一个简单的回退。

结果具有一个__wrapped__属性,可让您访问原始功能:

orig = _sftp_command_with_retries.__wrapped__

如果decorator未安装, 并且 您使用的是3.2之前的Python版本,则该属性将不存在;您必须手动进入装饰器闭合:

orig = _sftp_command_with_retries.__closure__[1].cell_contents

(索引0处的闭包是retry_decorator在调用retry()自身时产生的)。

需要注意的是decorator被列为依赖retry包的元数据,如果你安装它pipdecorator包会被自动安装。

您可以使用try...except

try:
    orig = _sftp_command_with_retries.__wrapped__
except AttributeError:
    # decorator.decorator not available and not Python 3.2 or newer.
    orig = _sftp_command_with_retries.__closure__[1].cell_contents

请注意,您 始终
可以time.sleep()使用模拟补丁。装饰器代码将使用该模拟程序,因为它引用了模块源代码中的“全局”time模块。

或者,您可以修补retry.api.__retry_internal

import retry.api
def dontretry(f, *args, **kw):
    return f()

with mock.patch.object(retry.api, '__retry_internal', dontretry):
    # use your decorated method

这会将执行实际重试的功能临时替换为直接调用原始功能的功能。