当前位置: 首页 > news >正文

pytest通过pytest_runtest_makereport添加失败截图到Allure报告中

一、介绍

在编程领域,hook 函数(钩子函数) 是一种在特定事件或流程发生时被自动调用的函数,用于拦截、修改或扩展原有程序的行为。它的核心作用是 “挂钩” 到程序的特定执行点,在不修改原有代码的前提下,实现自定义逻辑。

(1)核心特点

  • 触发时机固定:通常与特定事件绑定(如程序启动、函数调用前、数据处理后等)。
  • 非侵入式扩展:无需修改原有代码,通过注册 hook 函数即可扩展功能。
    灵活性高:可动态添加 / 移除,适应不同场景的需求。

(2)常见应用场景

  • 框架扩展很多测试框架(如 pytest)、Web 框架(如 Django)通过 hook 函数允许用户自定义流程。例如,pytest 的pytest_runtest_makereport钩子可用于在测试用例执行后生成自定义报告。
  • 事件拦截在 GUI 编程中,hook 函数可拦截鼠标点击、键盘输入等事件,实现自定义响应逻辑。
  • 日志与监控在函数调用前后插入 hook 函数,记录调用参数、返回值或执行时间,用于调试或性能监控。
  • 权限控制在接口请求处理前,通过 hook 函数验证用户权限,决定是否允许继续执行。

(3)pytest 中的 hook 函数示例

pytest 框架内置了大量 hook 函数,用于扩展测试流程。例如,自定义测试报告格式:

# conftest.py(pytest自动识别的钩子文件)
def pytest_runtest_makereport(item, call):"""在测试用例执行后生成报告"""if call.when == "call":  # 当测试用例执行时if call.excinfo is not None:  # 若测试失败print(f"用例 {item.nodeid} 执行失败!")

二、例:pytest_runtest_makereport

pytest_runtest_makereport 是 pytest 框架中一个非常重要的 钩子函数(hook function),用于在测试用例执行的不同阶段生成测试报告信息。它的核心作用是 拦截测试用例的执行过程,获取执行状态、结果和详细信息,方便开发者自定义测试报告、记录日志或执行失败后的操作(如截图)。

2. 关键参数解析

def pytest_runtest_makereport(item, call):# ...

(1)item

测试用例对象,包含用例的元信息,如:

  • item.nodeid:用例的唯一标识(格式如 文件名::类名::方法名)。
  • item.function:测试函数对象,可通过 item.function.__doc__ 获取用例文档字符串(描述信息)。

(2)call

测试用例执行的调用对象,包含执行过程中的细节,如:

  • call.when:标记当前执行阶段("setup"/"call"/"teardown")。
  • call.excinfo:执行过程中抛出的异常信息(若有),可用于获取错误堆栈。

3. 执行阶段(call.when)

测试用例的执行分为三个阶段,pytest_runtest_makereport 会在每个阶段被调用一次:

  • "setup":测试用例的前置操作阶段(如 fixture 的前置代码)。
  • "call":测试用例的核心执行阶段(即测试函数本身的逻辑)。
  • "teardown":测试用例的后置操作阶段(如 fixture 的后置代码,如 driver.quit())。

通过判断 call.when,可以针对性地处理不同阶段的逻辑(例如只关注 call 阶段的失败)。

4. 返回值与 TestReport 对象

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):# 可以获取测试用例的执行结果,yield,返回一个result对象out = yieldres = out.get_result()

函数中通过 out = yield 暂停执行,等待测试阶段完成后,out.get_result() 会返回一个 TestReport 对象

TestReport对象 包含的核心属性:

  • obj.when:同 call.when,标识当前阶段。
  • obj.outcome:测试结果("passed" 成功 / "failed" 失败 / "skipped" 跳过)。
  • obj.nodeid:用例唯一标识(同 item.nodeid)。
  • obj.longrepr:详细的执行日志(失败时包含错误堆栈信息)。
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):# 可以获取测试用例的执行结果,yield,返回一个result对象out = yield"""返回一个result对象(out)获取调用结果的测试报告,返回一个report对象report对象的属性包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、outcome(用例的执行结果:passed,failed)"""res = out.get_result()print("执行结果:{}".format(res))if res.when == "call" and res.outcome == "failed":  # 只获取call用例失败时的信息print("测试用例:{}".format(item))print("用例描述:{}".format(item.function.__doc__))print("测试步骤:{}".format(call))print("用例失败异常信息:{}".format(call.excinfo))print("用例失败时的详细日志:{}".format(res.longrepr))

5. 实际应用场景

最常见的用法是 在测试用例失败时自动记录信息或截图(结合 Selenium 等工具)。下例:在自动化测试中捕获失败的测试用例并自动添加截图到 Allure 报告中。

import allure
import pytestfrom selenium import webdriver# 用例前后置
@pytest.fixture(scope="package")
def driver_fix():# 用例前置# 初始化浏览器对象并启动浏览器driver = webdriver.Chrome()# 返回浏览器对象给用例yield driver# 用例的后置处理:关闭浏览器driver.quit()@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):# 可以获取测试用例的执行结果,yield,返回一个result对象out = yield"""返回一个result对象(out)获取调用结果的测试报告,返回一个report对象report对象的属性包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、outcome(用例的执行结果:passed,failed)"""report = out.get_result()# 仅仅获取用例call阶段的执行结果,不包含setup和teardownif report.when == 'call':# 获取用例call执行结果为结果为失败的情况# 从测试用例的参数中获取 driver(fixture 名为 driver_fix)driver = item.funcargs.get("driver_fix")if driver:  # 确保 driver 存在且未被关闭"""hasattr(对象, 属性或方法的名称)用于判断对象是否具有指定的属性或方法。函数返回一个布尔值,如果对象具有指定的属性或方法,则返回True,否则返回False。"""# 检查报告对象中是否有wasxfail属性,表示测试用例是否被标记为预期失败(xfail)xfail = hasattr(report, "wasxfail")# 如果测试用例被跳过且是预期失败,或者测试用例执行失败且不是预期失败if (report.skipped and xfail) or (report.failed and not xfail):# 添加allure报告截图with allure.step("添加失败截图"):# 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名、文件类型allure.attach(driver.get_screenshot_as_png(), "失败截图", allure.attachment_type.PNG)

(1)解析

钩子函数定义
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport():out = yieldreport = out.get_result()
  • @pytest.hookimpl(hookwrapper=True):这是 pytest 的钩子装饰器,hookwrapper=True 表示这个钩子会包装原有的 pytest 行为。
  • pytest_runtest_makereport:这是 pytest 内置的钩子函数,用于在测试用例执行的不同阶段(setup、call、teardown)生成测试报告。
  • out = yield:暂停钩子执行,让 pytest 执行实际的测试逻辑,然后通过 out.get_result() 获取测试结果(即 report 对象)。
判断测试结果
xfail = hasattr(report, "wasxfail")
if (report.skipped and xfail) or (report.failed and not xfail):# ...
  • xfail:判断测试是否被标记为 预期失败(通过 @pytest.mark.xfail 装饰器)。
  • 触发截图的条件
    • report.skipped and xfail:测试被跳过且是预期失败(例如,预期失败的条件未满足)。
    • report.failed and not xfail:测试实际失败且不是预期失败。
添加截图到 Allure 报告
with allure.step("添加失败截图"):allure.attach(driver.get_screenshot_as_png(), "失败截图", allure.attachment_type.PNG)
  • allure.step:在 Allure 报告中创建一个步骤节点,便于结构化展示。
  • allure.attach:将截图作为附件添加到报告中:
    • driver.get_screenshot_as_png():调用 Selenium 的 WebDriver 获取当前页面截图(假设 driver 是全局变量或通过 fixture 注入)。
    • "失败截图":附件的名称,会显示在报告中。
    • allure.attachment_type.PNG:指定附件类型为 PNG 图片。

(2)扩展:预期失败(xfail)

使用 @pytest.mark.xfail 标记一个测试用例时,表示:

  • 预期这个测试会失败(例如,测试一个尚未修复的 bug 或未实现的功能)。
  • 如果测试实际失败,pytest 会将其标记为 XPASS(预期失败但实际通过,可能表示 bug 已修复)。
  • 如果测试实际通过,pytest 会将其标记为 XFAIL(预期失败且实际失败,符合预期)。
wasxfail 属性的作用
  • 当测试用例被标记为 xfail 且实际执行结果为 失败 时,测试报告对象(report)会包含 wasxfail 属性,值为 True
  • 若测试用例未被标记为 xfail,或标记了但实际通过(XPASS),则 report 对象不会有 wasxfail 属性。

6. 完整实践代码简单示例

conftest.py

#!/usr/bin/env python
# encoding: utf-8import allure
import pytestfrom selenium import webdriver# 用例前后置
@pytest.fixture(scope="package")
def driver_fix():# 用例前置# 初始化浏览器对象并启动浏览器driver = webdriver.Chrome()# 返回浏览器对象给用例yield driver# 用例的后置处理:关闭浏览器driver.quit()@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(item, call):# 可以获取测试用例的执行结果,yield,返回一个result对象out = yield"""返回一个result对象(out)获取调用结果的测试报告,返回一个report对象report对象的属性包括when(setup,call,teardown三个值)、nodeid(测试用例的名字)、outcome(用例的执行结果:passed,failed)"""report = out.get_result()# 仅仅获取用例call阶段的执行结果,不包含setup和teardownif report.when == 'call':# 获取用例call执行结果为结果为失败的情况# 从测试用例的参数中获取 driver(fixture 名为 driver_fix)driver = item.funcargs.get("driver_fix")if driver:  # 确保 driver 存在且未被关闭"""hasattr(对象, 属性或方法的名称)用于判断对象是否具有指定的属性或方法。函数返回一个布尔值,如果对象具有指定的属性或方法,则返回True,否则返回False。"""# 检查报告对象中是否有wasxfail属性,表示测试用例是否被标记为预期失败(xfail)xfail = hasattr(report, "wasxfail")# 如果测试用例被跳过且是预期失败,或者测试用例执行失败且不是预期失败if (report.skipped and xfail) or (report.failed and not xfail):# 添加allure报告截图with allure.step("添加失败截图"):# 使用allure自带的添加附件的方法:三个参数分别为:源文件、文件名、文件类型allure.attach(driver.get_screenshot_as_png(), "失败截图", allure.attachment_type.PNG)

test_case.py

#!/usr/bin/env python
# encoding: utf-8
'''
@Software: PyCharm
@File    : test_case.py
@Time    : 2023/8/29 17:01
@desc   : 
'''
from time import sleepimport allure@allure.title("百度搜索")
def test_baidu(driver_fix):"""百度搜索测试用例"""driver = driver_fixdriver.get('http://www.baidu.com')sleep(1)driver.find_element('id', 'kw').send_keys('allure报告失败截图')sleep(1)driver.find_element('id', 'su').click()sleep(1)assert driver.title == "11allure报告失败截图_百度搜索"sleep(3)

main_run.py

#!/usr/bin/env python
# encoding: utf-8import os
import pytestdef run():# pytest.main(['-sv'])pytest.main(['-v', 'test_case.py', '--alluredir', './result', '--clean-alluredir'])os.system('allure generate ./result/ -o ./report --clean')if __name__ == '__main__':run()

报告截图

三个文件在同一层目录下,运行main_run.py文件,生成的report用浏览器打开后如下图:
在这里插入图片描述

http://www.dtcms.com/a/268612.html

相关文章:

  • 常见问题与最佳实践——AI教你学Docker
  • 1-Kafka介绍及常见应用场景
  • 学习基于springboot秒杀系统-环境配置(接口封装,mybatis,mysql,redis(Linux))
  • 2025年全国青少年信息素养大赛图形化(Scratch)编程小学低年级组初赛样题答案+解析
  • 登山第二十六梯:单目3D检测一切——一只眼看世界
  • 【C++开源库使用】使用libcurl开源库发送url请求(http请求)去下载用户头像文件(附完整源码)
  • 【R语言】 在读取 CSV 或 Excel 文件时的标准输出
  • 自定义简单线性回归模型
  • 【AI大模型】神经网络反向传播:核心原理与完整实现
  • 电脑电压过高的影响与风险分析
  • 轨迹优化 | 基于激光雷达的欧氏距离场ESDF地图构建(附ROS C++仿真)
  • 回溯题解——子集【LeetCode】二进制枚举法
  • ssh: Could not resolve hostname d: Temporary failure in name resolution
  • 从依赖地狱到依赖天堂PNPM
  • 01、通过内网穿透工具把家中闲置电脑变成在线服务器
  • C盘瘦身 -- 虚拟内存文件 pagefile.sys
  • (六)PS识别:源数据分析- 挖掘图像的 “元语言”技术实现
  • python list去重
  • 【Behavior Tree】-- 行为树AI逻辑实现- Unity 游戏引擎实现
  • Docker 将镜像打成压缩包将压缩包传到服务器运行
  • 物联网技术的关键技术与区块链发展趋势的深度融合分析
  • Java SE与Java EE使用方法及组件封装指南
  • 安卓10.0系统修改定制化_____安卓9与安卓10系统文件差异 有关定制选项修改差异
  • Java 并发编程中的同步工具类全面解析
  • qiankun隔离机制
  • [附源码+数据库+毕业论文]基于Spring+MyBatis+MySQL+Maven+jsp实现的高校实验室资源综合管理系统,推荐!
  • 按键开关:新型防水按键开关的特点!
  • 音频流媒体技术选型指南:从PCM到Opus的实战经验
  • 【Java面试】Https和Http的区别?以及分别的原理是什么?
  • 02 除了前面常见图表,还有许多更细分或专业的可视化类型,尤其是在特定领域(如金融、工程、生物信息等)。