You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用@pytest.hookimpl(tryfirst=True)触发AttributeError问题求助

问题分析与解决

错误原因

你遇到的AttributeError: generator object has no attribute 'skipped',核心原因是**@pytest.hookimpl装饰的函数不能是生成器(不能使用yield)**:

  • 原代码用@pytest.mark.hookwrapper时,函数允许以生成器形式存在,通过yield获取测试执行的outcome对象,再通过outcome.get_result()拿到真实的TestReport实例,此时report是测试报告对象,具备skipped等属性。
  • 改用@pytest.hookimpl(tryfirst=True)后,你保留了yield语句,导致函数返回的是生成器对象,而非预期的测试报告对象,自然没有skipped属性。

解决方案

方案1:继续使用hookwrapper(推荐)

如果你的需求是拦截并修改测试报告(比如嵌入截图),@pytest.mark.hookwrapper是pytest专门设计用于这类场景的装饰器,完全适配你的现有逻辑,不需要更换装饰器。原代码本身是可行的,只需保留原装饰器即可:

@pytest.mark.hookwrapper
def pytest_runtest_makereport(item):
    """
    Extends the PyTest Plugin to take and embed screenshot in html report, whenever test fails.
    :param item:
    """
    pytest_html = item.config.pluginmanager.getplugin('html')
    outcome = yield
    report = outcome.get_result()
    extra = getattr(report, 'extra', [])

    if report.when == 'call' or report.when == "setup":
        xfail = hasattr(report, 'wasxfail')
        if (report.skipped and xfail) or (report.failed and not xfail):
            clean_nodeid = report.nodeid.replace("tests/", "")
            file_name = ("./reports/screenshots/" + clean_nodeid.replace("::", "_") + ".png")
            driver.get_screenshot_as_file(file_name)
            screenshot = driver.get_screenshot_as_base64()
            extra.append(pytest_html.extras.image(screenshot, ""))

        report.extra = extra

方案2:改用@pytest.hookimpl(需重构代码)

如果一定要使用@pytest.hookimpl,需要调整函数结构,遵循该装饰器的要求:

  • 函数不能是生成器,需去掉yield
  • 函数签名要符合pytest_runtest_makereport的标准:接收item和call两个参数
  • 生成或修改测试报告后返回

示例代码如下:

@pytest.hookimpl(tryfirst=True)
def pytest_runtest_makereport(item, call):
    pytest_html = item.config.pluginmanager.getplugin('html')
    # 获取原始测试报告
    report = item.config.hook.pytest_runtest_makereport(item=item, call=call)
    extra = getattr(report, 'extra', [])

    if report.when == 'call' or report.when == "setup":
        xfail = hasattr(report, 'wasxfail')
        if (report.skipped and xfail) or (report.failed and not xfail):
            clean_nodeid = report.nodeid.replace("tests/", "")
            file_name = ("./reports/screenshots/" + clean_nodeid.replace("::", "_") + ".png")
            driver.get_screenshot_as_file(file_name)
            screenshot = driver.get_screenshot_as_base64()
            extra.append(pytest_html.extras.image(screenshot, ""))

        report.extra = extra
    return report

注意:这种方式需要确保你正确调用原始的hook获取报告,部分场景下可能会出现hook执行顺序的问题,因此更推荐方案1。

内容的提问来源于stack exchange,提问作者Luis

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 23:42:44