本文承接前作《pytest 钩子:pytest_report_teststatus 实践》与《pytest 钩子:pytest_collection_finish 实践》。前两篇解决了「数据从哪里来」的问题------通过 pytest 钩子上报用例采集与执行结果;本文聚焦「数据到哪里去」------基于 Golang + Echo 搭建一套前后端服务,对钩子上报的数据做汇总、持久化与可视化,最终形成一份可检索、可下钻、可追溯、可扭转的动态测试报告,让 pytest 的产出真正服务于研发与测试协同。
一、背景与整体思路
1.1 为什么需要这层服务
pytest 生态里并不缺报告方案:自带 --html、--junit-xml,社区有 allure、pytest-reporter 等。但绝大多数方案本质上都是一次性产物,存在几个长期痛点:
- 跑完才生成:执行过程中无法看到状态,进程被杀或异常退出就一切归零;
- 每次跑完覆盖:同一份报告文件下一次跑就丢,无法沉淀历史,无法跨任务对比;
- 失败用例靠记忆:「这条上次是不是同一个问题、上次怎么处理、谁处理过」完全靠人脑记忆与群消息翻屏;
- 多人多机器散落:本地、CI、定时任务各跑各的,报告文件散落各处,难以统一分发与归档。
而通过 pytest 钩子实时上报 + Golang 后端汇总 的架构,可以把每一次执行沉淀为一条「任务记录」、把每一条用例沉淀为一条「用例记录」,并支持后续的检索、评审、追溯------让报告从一次性产物变成持续演进的资产。
1.2 整体架构
┌──────────────┐ pytest hooks ┌──────────────────────┐ ┌──────────────────┐
│ pytest runner│ ───────────────▶ │ Golang + Echo Server │◀──────▶│ MySQL / Storage │
│ (collection, │ HTTP POST │ /autotest/task/... │ │ task / case / │
│ report) │ │ REST API │ │ review / history │
└──────────────┘ └──────────────────────┘ └──────────────────┘
│
│ JSON
▼
┌──────────────────┐
│ Frontend (HTML/ │
│ JS / CSS) │
│ 可视化交互层 │
└──────────────────┘
整体分为三层:
- 采集层 :
pytest_collection_finish钩子上报用例采集结果(用例总数、Node ID、markers);pytest_report_teststatus钩子上报用例执行结果(pass/fail/skip、duration、traceback)。 - 服务层:Golang + Echo 提供 RESTful 接口,负责数据汇总、查询、评审、历史、导出、生成测试缓存、删除。
- 展示层:原生 HTML + 原生 JS(无重型框架)实现三层弹窗下钻交互,配合 Toastify 提示。
二、功能总览
整套服务围绕「测试任务」一个核心页面对外暴露能力,自上而下分成四个递进功能:
| 功能 | 入口 | 解决什么 |
|---|---|---|
| 功能 1:任务列表可视化 | /autotest/task/index |
多任务概览、检索、分发、归档 |
| 功能 2:任务详情可视化 | 列表点「查看」 | 单任务下钻到用例级 |
| 功能 3:失败用例详情与状态扭转 | 详情中点失败用例 | 失败用例人工评审与状态扭转 |
| 功能 4:用例历史追溯 | 评审弹窗点「查看历史」 | 同一用例跨任务的历史轨迹 |
下面分别展开。
三、功能 1:任务列表可视化
3.1 功能介绍
对测试任务的数据进行简要可视化,作为平台首页与门户。具体能力包括:
- 对测试任务进行可视化展示,直观展示测试任务用例总数、成功、失败、跳过、未执行等用例状态的数量;
- 支持对测试任务的过滤搜索;
- 支持按任务名称、通过率、时间等字段排序;
- 支持一键导出测试数据;
- 支持一键生成测试缓存数据。
3.2 字段与交互
任务列表以表格形式呈现,每行对应一次测试任务,列含义如下:
| 列名 | 含义 | 可排序 |
|---|---|---|
| 任务名称 | 任务的唯一标识,点击可进入任务详情 | ✅ |
| 总数 | 该任务下用例总数 | ✅ |
| 成功 | 执行通过的用例数 | --- |
| 失败 | 执行失败的用例数 | --- |
| 跳过 | 被 skip 的用例数 | --- |
| 已排查 | 人工复核过、已确认状态的用例数 | --- |
| 未执行 | 未跑出结果的用例数(unknown) | --- |
| 通过率 | Passed / Total 的百分比 | ✅ |
| 时间 | 任务创建时间 | ✅ |
| 操作 | 查看 / 导出 / 缓存 三个动作 | --- |
- 搜索:顶部搜索框支持按任务名称模糊匹配,点击「搜索」按钮或回车触发,客户端过滤响应极快;
- 分页:10 / 50 / 100 条每页可切,支持跳转到指定页;
- 行操作:「查看」进入详情,「导出」生成下载链接,「缓存」生成失败用例缓存压缩包。
3.3 效果
四、功能 2:任务详情可视化
4.1 功能介绍
对测试任务做更详细的可视化,从「任务级」下钻到「用例级」。具体能力:
- 详细展示测试任务的用例总数与通过率,以及各个状态(成功 / 失败 / 跳过 / 未执行)用例数量;
- 详细展示测试任务的用例名称、耗时、状态、Node ID 等信息;
- 支持对测试用例的搜索;
- 支持按用例状态过滤用例;
- 支持按用例执行耗时排序。
4.2 筛选与排序
详情弹窗顶部提供三个筛选/排序控件:
- 按用例名或 NodeID 筛选 :实时
oninput过滤,匹配用例名或node_id(如tests/test_login.py::test_login_ok); - 按结果筛选 :下拉框,选项包含 全部 / 通过 / 失败 / 跳过 / 已排查 / 未执行;
- 按耗时排序 :点击「耗时 ↕」按钮在 降序 → 升序 → 不排序 三态之间循环,便于定位最慢用例。
筛选区右侧实时显示 已匹配 / 总数 计数,方便确认当前过滤结果范围。
4.3 用例列表
筛选后的用例以表格呈现,列包括:用例名 / 结果 / 耗时 / Node ID 。结果列会附加状态徽标(已排查、已标记通过)。对失败或已排查用例,Node ID 与 结果 单元格均可点击,进入失败详情与评审弹窗。
4.4 效果
五、功能 3:失败用例详情与状态扭转
5.1 功能介绍
针对失败用例,在排查过程中为了避免重复排查或排查遗漏,平台引入了「用例状态扭转」机制。具体能力:
- 展示用例的基本信息(用例名称、当前状态);
- 展示当前失败的 Traceback(渲染时会把
Error/Exception/Traceback等关键行高亮,便于一眼定位异常抛出点); - 支持状态扭转(已排查 / 标记通过);
- 支持添加本次排查的备注信息;
- 支持查看历史排查数据。
5.2 状态扭转的设计意图
pytest 原生结果只有 passed / failed / skipped 三态,缺乏「人工评审」这一维度。平台在用例上叠加了一层 review_status:
- 已排查:明确为「这条失败我看过、是预期内的」,但不改变结论;
- 标记通过:明确为「这条不再视为失败」,下次回归该用例不再被记为失败。
这样在跨任务对比时,可以快速区分「真正的新增失败」与「已知问题」,让回归报告的可信度大幅提升。
5.3 效果
六、功能 4:用例历史追溯
6.1 功能介绍
「查看历史」用于追溯某个用例过去所有的执行与评审轨迹,对偶发问题、环境问题的判定非常友好。具体能力:
- 支持展示历史的排查数据(排查人员、时间、排查结果、当时的报错 traceback、备注信息);
- 支持查看某条历史 Traceback 的详细日志。
6.2 价值
切换查看某条历史 traceback 时,标题会自动改为 (历史 #N:时间),方便区分「最新」与「某次历史」。这样排查同学既能看到「现在长什么样」,也能看到「过去什么时候变过、为什么变」,对偶发问题、环境问题、时序问题的判定非常友好。
6.3 效果
七、与 pytest 钩子的协作
本服务的数据全部由 pytest 端的钩子上报而来,二者协同形成一个闭环。
7.1 pytest_collection_finish:上报采集结果
在用例收集完成后触发,把整批用例的 Node ID、名称、markers 一次性上报到后端,形成「待执行用例」集合。这一步是「未执行(unknown)」状态的来源------后续若某条用例没出现在 pytest_report_teststatus 上报中,则会一直保留为 unknown,便于发现用例被静默 skip / 收集失败的情况。
7.2 pytest_report_teststatus:上报执行结果
每个用例执行完触发,把 pass/fail/skip、duration、traceback 等实时上报,后端据此更新对应用例的状态。这样即便测试中断(如进程被杀),也已经留存了已执行部分的结果,比「跑完才生成报告」的传统方案更稳健。
7.3 1+1>2 的效果
- 单独的钩子只是「事件源」,没有可视化就只能看日志;
- 单独的可视化如果数据是静态文件,就失去了「动态、可沉淀」的优势;
- 钩子 + 服务 的组合,让每一次 pytest 执行都自动成为平台上的一个可查、可评、可追溯的任务,真正实现动态报告。
八、典型使用场景
- 回归报告查阅:日常回归跑完后,进入「测试任务」列表,按通过率排序,找到本次回归任务,点「查看」查看失败用例与未执行用例。
- 失败用例排查 :在任务详情弹窗中按结果筛选
failed,点击失败用例的 NodeID 查看 Traceback,结合堆栈与备注判断是产品 Bug、用例问题还是环境问题。 - 状态扭转:确认是已知问题后,在评审弹窗填写备注并点击「已排查」或「标记通过」,下次回归该用例不再被记为失败。
- 历史追溯:对偶发失败用例,点「查看历史」回看历次执行与评审记录,对比不同时间点的 Traceback,定位问题是否发生变化。
- 结果分发:点击「导出」生成下载链接,复制后贴到群消息或工单中,让相关同学离线查看完整报告。
- 缓存重试:点击「缓存」生成失败用例缓存压缩包,提供下载地址,基于失败缓存快速重试失败用例。
九、小结
服务的「测试任务」模块把「跑测试」之后的全部动作都收口到了一个页面里:列表概览 → 用例下钻 → 失败排查 → 评审扭转 → 历史追溯 形成完整闭环。
从技术视角看,它做了三件有价值的事:
- 把 pytest 钩子的「事件流」沉淀为「数据资产」------通过 Golang + Echo 把零散的钩子上报聚合为可查询的任务/用例记录;
- 把「一次性报告」升级为「动态报告」------支持评审扭转与历史追溯,让用例状态会随着人不断介入而演进;
- 把「个人跑测」升级为「团队协同」------导出、缓存、登录态保护,让测试结果天然具备分发与协同属性。
这正是 1+1>2 的效果:pytest 钩子负责「采得全」,Golang 服务负责「存得久、查得动」,前端负责「看得清、用得上」,三者一起构成了一套面向自动化测试结果的实用型可视化平台。
相关阅读
- 《pytest 钩子:pytest_report_teststatus 实践》------介绍如何上报用例执行结果
- 《pytest 钩子:pytest_collection_finish 实践》------介绍如何上报用例采集结果