如何在python中测试时删除装饰器的效果?

时间:2015-09-21 14:19:25

标签: python testing mocking

我在python中的某些代码中使用了retry装饰器。但我希望通过消除它的影响来加速我的测试。

我的代码是:

@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,但由于这是在装饰器中我不会认为&# 39;可能。

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

更新

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

所以从here我可以看到如何模拟装饰器。但现在我需要知道如何编写一个本身就是装饰器的模拟器。它需要调用_sftp_command_with_retries,如果它引发异常,则传播它,否则返回返回值。

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

_sftp_command_with_retries = _sftp_command_with_retries.__wrapped__ 

1 个答案:

答案 0 :(得分:6)

retry decorator you are using建立在decorator.decorator utility 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()

请注意,decoratorretry包元数据中列为依赖项,如果您使用pip安装decorator,则会自动安装try...except包。 / p>

您可以使用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。装饰器代码将使用模拟,因为它引用了全局' the module source code中的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

{{1}}

这暂时将用实际重试的函数替换为直接调用原始函数的函数。