pytest 如何让失败用例自动保存截图/日志(pytest-selenium示例)
技术百科
冷漠man
发布时间:2026-01-25
浏览: 次 pytest-selenium失败时需通过fixture中addfinalizer在teardown阶段检查request.node.rep_call.failed并调用driver.save_screenshot()实现自动截图,路径建议含时间戳和用例名;官方已移除screenshot_on_failure参数,须手动实现。
pytest-selenium 失败时怎么自动截图
默认情况下 pytest-selenium 不会自动截图,必须显式调用 driver.save_screenshot()。要实现「失败自动截图」,得靠 pytest 的钩子函数,在用例结束且状态为失败时触发保存逻辑。
关键点是使用 pytest_runtest_makereport 钩子获取测试结果,并在 teardown 阶段(或 exception 时)调用截图。但注意:此时 driver 实例可能已被 quit() —— 所以截图动作必须放在 driver 关闭前,通常绑定到 request.addfinalizer 或 fixture 的 teardown 中。
- 推荐把 driver 初始化写在 fixture 里,用
scope="function"确
保每个用例独立
- 在 fixture 的 teardown 部分检查是否失败(通过
request.node.rep_call.failed),再截图 - 截图路径建议带时间戳和用例名,避免覆盖:
f"screenshots/{request.node.name}_{int(time.time())}.png"
如何在 fixture 中安全访问测试结果
pytest 的 request.node 在测试执行完后才填充 rep_call 属性,所以不能在 fixture setup 阶段读,而要在 finalizer 里延迟读取。常见错误是直接在 fixture 返回 driver 前就尝试读 rep_call,此时它还是 None。
正确做法是用 request.addfinalizer() 注册一个清理函数,该函数在测试函数执行完毕后运行,此时 request.node.rep_call 已就绪:
@pytest.fixture
def driver(request):
driver = webdriver.Chrome()
def fin():
if request.node.rep_call and request.node.rep_call.failed:
timestamp = int(time.time())
name = request.node.name.replace("[", "_").replace("]", "_")
driver.save_screenshot(f"screenshots/{name}_{timestamp}.png")
driver.quit()
request.addfinalizer(fin)
return driver
注意:rep_call 只对 call 阶段(即测试函数本身)有效;setup/teardown 失败会写入 rep_setup 或 rep_teardown,需分别判断。
pytest-selenium 自带的 screenshot_on_failure 参数有用吗
没用。pytest-selenium 早期版本曾提供 --screenshot-on-failure 命令行参数,但自 2.0+ 起已移除,文档也未保留。当前 PyPI 上最新版(如 4.x)完全不支持该参数,传了也不会生效,还会被 pytest 忽略或报错 unrecognized arguments。
- 不要依赖
--screenshot-on-failure或screenshot_on_failure=True这类配置 - 官方推荐方式就是手动 hook + fixture 控制,灵活性更高
- 如果项目用了
pytest-base-url或pytest-html,可配合生成带截图链接的报告,但截图动作仍需自己写
日志怎么同步保存(非截图)
浏览器控制台日志(console logs)、网络请求(performance logs)、Selenium 日志都不能靠截图捕获,得主动拉取。失败时最实用的是 driver.get_log("browser"),但要注意:logging_prefs 必须在 driver 初始化时开启,否则返回空列表。
示例(在 fixture 初始化 driver 时):
options = webdriver.ChromeOptions()
options.set_capability("goog:loggingPrefs", {"browser": "ALL"})
driver = webdriver.Chrome(options=options)
然后在 finalizer 的失败分支中追加:
if request.node.rep_call.failed:
logs = driver.get_log("browser")
with open(f"logs/{name}_{timestamp}.log", "w") as f:
for entry in logs:
f.write(f"[{entry['level']}] {entry['timestamp']}: {entry['message']}\n")
容易忽略的是:不同浏览器日志类型不同("browser" 是 Chrome/Firefox 支持的,Edge 需用 "performance" 或 "driver"),而且 get_log() 在某些 Selenium 版本中对 headless 模式支持不稳定。
# ai
# 的是
# 放在
# 这类
# 还会
# 能在
# 用了
# 移除
# 并在
# 已被
# 要在
# 浏览器
# edge
# go
# int
# html
# console
# chrome
# function
# node
# firefox
# 命令行参数
# webdriver
# pytest
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- php订单日志怎么导出excel_php导出订单日
- php中::能访问全局变量吗_全局作用域与类作用域
- Win11如何开启telnet服务 Win11启用
- Win10怎么创建桌面快捷方式 Win10为应用创
- Win11怎么关闭小组件_Win11禁用任务栏天气
- Win11系统占用空间大怎么办 Win11深度瘦身
- 如何使用Golang构建基础消息队列模拟_Gola
- Mac系统更新下载慢或失败怎么办_解决macOS升
- 如何使用Golang捕获并记录协程panic_保证
- 如何用正则与预处理结合精准拦截拼接式垃圾域名
- VSC里PHP变量未定义报错怎么解决_错误抑制技巧
- Win11如何隐藏桌面图标 Win11一键隐藏/显
- Mac上的iMovie如何剪辑视频?(新手入门教程
- Python如何创建带属性的XML节点
- PHP主流架构如何做单元测试_工具与流程【详解】
- VSC怎么快速定位PHP错误行_错误追踪设置法【方
- 如何在Golang中修改数组元素_通过指针实现原地
- Win11怎么关闭用户账户控制UAC_Window
- 用Python构建微服务架构实践_FastAPI与
- Win10系统映像怎么恢复 Win10使用系统映像
- c++中如何计算坐标系中两点间距离_c++勾股定理
- Win11如何设置ipv6 Win11开启IPv6
- Windows10如何更改桌面背景_Win10个性
- 如何在 Go 开发中正确处理本地包导入与远程模块路
- Golang如何实现基本的用户注册_Golang用
- 如何使用Golang实现文件加密_Golang c
- 如何使用Golang开发简单的聊天室消息存储_Go
- Python 中将 ISO 8601 时间戳转换为
- 如何使用Golang实现跨域请求支持_Golang
- 微信企业付款回调PHP怎么接收_处理企业付款异步通
- 如何在Mac上搭建Golang开发环境_使用Hom
- Python大文件处理策略_内存优化说明【指导】
- Win11怎么更改系统语言为中文_Windows1
- MAC怎么使用表情符号面板_MAC Emoji快捷
- 如何在 Go 中创建包含 map 的 slice(
- 如何在Golang中实现CI/CD流水线自动化测试
- Win11怎么设置虚拟内存_Windows 11优
- Win11系统更新后黑屏怎么办 Win11更新黑屏
- Win11怎么关闭防火墙通知_屏蔽Win11安全中
- Windows10怎么用“讲述人”读屏辅助 Win
- Win11怎么设置DNS服务器_Windows11
- 如何使用Golang实现云原生应用弹性伸缩_自动应
- 如何使用Golang recover捕获panic
- Win10怎样卸载DockerDesktop_Wi
- 为什么本地php环境运行php脚本卡顿_php执行
- 如何高效删除 NumPy 二维数组中所有元素相同的
- Python函数接口稳定性_版本演进解析【指导】
- PHP中require语句后直接调用返回对象方法的
- Win11怎么关闭搜索历史_Win11清除任务栏搜
- php怎么下载安装后测试是否成功_简单脚本验证方法


QQ客服