如何在 python 中测试时移除装饰器的效果?
How to remove the effects of a decorator while testing in python?
我在 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
但由于这是在装饰器中,我认为这是不可能的。
有什么方法可以加快使用此函数的测试代码?
更新
我基本上是在尝试测试使用它的更高级别的函数,以确保它们捕获 _sftp_command_with_retries
抛出的任何异常。由于 retry
装饰器将传播它们,我需要一个更复杂的模拟。
所以从 here 我可以看到如何模拟装饰器。但现在我需要知道如何编写一个本身就是装饰器的模拟。它需要调用 _sftp_command_with_retries
,如果它引发异常,传播它,否则 return return 值。
导入我的函数后添加这个不起作用:
_sftp_command_with_retries = _sftp_command_with_retries.__wrapped__
如果未安装该软件包,retry
decorator you are using is built on top of the 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()
本身时产生的 retry_decorator
)。
请注意 decorator
在 retry
包元数据中被列为依赖项,如果您使用 pip
安装它,decorator
包将自动安装.
您可以通过 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()
。装饰器代码将使用模拟,因为它引用 the module source code.
中的 'global' 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
这暂时用直接调用原始函数的函数替换了执行实际重试的函数。
我在 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
但由于这是在装饰器中,我认为这是不可能的。
有什么方法可以加快使用此函数的测试代码?
更新
我基本上是在尝试测试使用它的更高级别的函数,以确保它们捕获 _sftp_command_with_retries
抛出的任何异常。由于 retry
装饰器将传播它们,我需要一个更复杂的模拟。
所以从 here 我可以看到如何模拟装饰器。但现在我需要知道如何编写一个本身就是装饰器的模拟。它需要调用 _sftp_command_with_retries
,如果它引发异常,传播它,否则 return return 值。
导入我的函数后添加这个不起作用:
_sftp_command_with_retries = _sftp_command_with_retries.__wrapped__
如果未安装该软件包,retry
decorator you are using is built on top of the 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()
本身时产生的 retry_decorator
)。
请注意 decorator
在 retry
包元数据中被列为依赖项,如果您使用 pip
安装它,decorator
包将自动安装.
您可以通过 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()
。装饰器代码将使用模拟,因为它引用 the module source code.
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
这暂时用直接调用原始函数的函数替换了执行实际重试的函数。