【每日一题】失败自动重试装饰器(附参考答案)

题目:UI 自动化用例偶发失败(网络抖动、元素偶现加载慢),团队想给用例加"失败自动重试"。请实现装饰器 retry:被装饰函数抛异常时最多重试 retries 次(含首次共 retries+1 次执行),重试间隔 delay 秒;全部失败后抛出最后一次的异常;成功则直接返回结果。

代码框架:

import time

def retry(retries=2, delay=1):
    """
    @retry(retries=2, delay=1) 表示:失败后再试2次,每次间隔1秒
    """
    # 请在此处补全
    pass


# 测试:counter 记录执行次数,前两次抛异常,第三次成功
counter = {"n": 0}

@retry(retries=2, delay=0)
def flaky():
    counter["n"] += 1
    if counter["n"] < 3:
        raise ValueError("flaky fail")
    return "ok"

assert flaky() == "ok" and counter["n"] == 3

counter2 = {"n": 0}

@retry(retries=1, delay=0)
def always_fail():
    counter2["n"] += 1
    raise RuntimeError("boom")

try:
    always_fail()
    raised = False
except RuntimeError:
    raised = True

assert raised and counter2["n"] == 2

难度:中级
题型:笔试(编程题)

:point_right:参考答案/答题要点:

参考题解:

import time
from functools import wraps

def retry(retries=2, delay=1):
    def deco(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for attempt in range(retries + 1):
                try:
                    return func(*args, **kwargs)
                except Exception:
                    if attempt == retries:   # 最后一次机会也失败了
                        raise
                    time.sleep(delay)
        return wrapper
    return deco

采分点:①三层嵌套结构(装饰器工厂→deco→wrapper)写对,这是本题最大考点;②retries + 1 的执行次数语义;③最后一次失败要 raise 原异常,不能吞掉;④@wraps 保留函数名/docstring(pytest 用例名显示);⑤加分项:提"只对断言类异常重试、环境错误(找不到元素属于 setup 问题)不该重试"、“配合 pytest-rerunfailures 做用例级重试”。