python坚韧地重试,禁用unittest的“ wait”

Dan*_*tar 6 python unit-testing

我正在使用韧度库来使用其@retry装饰器。

我正在使用它来创建一个函数,该函数在失败的情况下多次重复执行HTTP请求。

这是一个简单的代码片段:

@retry(stop=stop_after_attempt(7), wait=wait_random_exponential(multiplier=1, max=60))
def func():
   ...
   requests.post(...)
Run Code Online (Sandbox Code Playgroud)

该函数使用强度wait参数在两次调用之间等待一段时间。

该函数与@retry-decorator 一起似乎正常工作。

但是我还有一个单元测试,可以检查该函数是否在发生故障的情况下被调用7次。由于wait在两次尝试之间进行了此测试,因此该测试需要大量时间。

是否可以以某种方式仅在单元测试中禁用等待时间?

Dan*_*tar 11

解决方案来自坚韧的维护者本人在这个 Github issue 中:https : //github.com/jd/tenacity/issues/106

您可以简单地临时更改单元测试的等待功能:

from tenacity import wait_none

func.retry.wait = wait_none()
Run Code Online (Sandbox Code Playgroud)


And*_*kin 6

在阅读tenacity repo 中的线程后(感谢 @DanEEStar 启动它!),我想出了以下代码:

@retry(
    stop=stop_after_delay(20.0),
    wait=wait_incrementing(
        start=0,
        increment=0.25,
    ),
    retry=retry_if_exception_type(SomeExpectedException),
    reraise=True,
)
def func() -> None:
    raise SomeExpectedException()


def test_func_should_retry(monkeypatch: MonkeyPatch) -> None:
    # Use monkeypatch to patch retry behavior.
    # It will automatically revert patches when test finishes.
    # Also, it doesn't create nested blocks as `unittest.mock.patch` does.

    # Originally, it was `stop_after_delay` but the test could be
    # unreasonably slow this way. After all, I don't care so much
    # about which policy is applied exactly in this test.
    monkeypatch.setattr(
        func.retry, "stop", stop_after_attempt(3)
    )

    # Disable pauses between retries.
    monkeypatch.setattr(func.retry, "wait", wait_none())

    with pytest.raises(SomeExpectedException):
        func()

    # Ensure that there were retries.
    stats: Dict[str, Any] = func.retry.statistics
    assert "attempt_number" in stats
    assert stats["attempt_number"] == 3
Run Code Online (Sandbox Code Playgroud)

pytest我在此测试中使用特定功能。也许,它对某人来说可能是有用的例子,至少对未来的我来说。


run*_*g.t 1

您可以使用unittest.mock模块来模拟tentacity库的一些元素。在您的情况下,您使用的所有装饰器都是类,例如是此处retry定义的装饰器类。所以这可能有点棘手,但我认为尝试

mock.patch('tentacity.wait.wait_random_exponential.__call__', ...)
Run Code Online (Sandbox Code Playgroud)

可能有帮助。