证据驱动测试
记录行为注释证明,然后将其附加到 PR 和跟踪问题。
录制是您通过计算机操作测试应用的过程:启动录制器,然后亲自驱动应用——点击、输入、导航——完成每个测试目标。视频中的每一个动作都是实时执行的测试;除非显示交互会话,否则录制作为证据没有价值。如果工具箱没有计算机操作工具但存在 GUI,请改用 cua-driver 驱动应用(见下文)——它仍然是您的实时会话。
捆绑的录制器 scripts/evidence.py 在 Linux、macOS 和 Windows 上使用 FFmpeg 捕获显示,在测试时为您添加的每个注释添加时间戳,在停止时将注释刻录到视频中,并使用 ffprobe 验证结果。它将 evidence.mp4、report.md 和 manifest.json 写入会话文件夹。
输入
- 测试目标(必需):要验证的行为/流程,以可测试的陈述形式表述。
- PR / 问题(可选):发布证据的位置。如果省略,则仅交付给请求者。
录制器
下面的 EVIDENCE 指的是此技能文件夹内 scripts/evidence.py 的路径(技能安装的位置,例如 ~/.claude/skills/evidence-driven-testing/scripts/evidence.py)。它仅需要 Python 3 和 FFmpeg。
-
首先检查:
python3 $EVIDENCE doctor— 验证ffmpeg、ffprobe、libx264和ass过滤器(ready),然后验证哪个屏幕捕获源在此机器上工作(capture_ready和源auto将选择)。仅在工具链缺失时输出非零退出码;在录制前读取capture_ready。 -
平台(
--source auto选择第一个可用的):操作系统 源 需要 Linux X11 / XWayland x11(x11grab)设置 DISPLAYLinux Wayland wayland(wf-recorder)设置 WAYLAND_DISPLAY,wf-recorder在 PATH 中,并且合成器确认支持 wlr-screencopy — 要么是已知的 wlroots 合成器(Sway、Hyprland、river、Wayfire、labwc、dwl、niri),要么通过wayland-info验证。GNOME 和 KDE 的 Wayland 无法通过此方式捕获;doctor会说明。对于 X11 应用,通过 XWayland 使用x11,或使用备用录制器。--source wayland仍然强制使用它macOS avfoundation授予终端/代理主机应用屏幕录制权限; doctor列出--screen-index的屏幕索引Windows gdigrab任何标准 ffmpeg 构建; powershell用于进程检查默认捕获整个屏幕;
--geometry WxH和--offset X,Y在 x11、wayland 和 gdigrab 上裁剪区域。XWayland 只能看到 X11 窗口,因此当被测应用是 Wayland 原生应用时,优先使用wayland源。 -
崩溃安全原始捕获:原始录制是 MPEG-TS(
raw.ts),因此如果录制器被强制杀死或崩溃,捕获的内容仍然可以探测和渲染。stop将其重新混合或重新编码为标准evidence.mp4。 -
停止方式:在 Linux 上,录制器通过 pidfd 接收信号。在 macOS 和 Windows 上,
start启动一个拥有 ffmpeg 子进程的小型监督进程,stop通过会话文件夹中的stop.request请求它中断、然后终止、最后杀死子进程;完成后写入recorder-exit.json。绝不会对裸 PID 发送信号,因此不会误杀已回收的 PID。如果监督进程在录制器仍在运行时死亡,stop会拒绝并告诉您哪个 PID 需要手动停止。如果监督进程在记录其启动的进程之前就死亡,stop会保持阻塞,直到您检查了是否有残留的录制器并使用--accept-untracked-recorder重新运行它;然后报告会附带该注意事项。 -
备用录制器,当
doctor报告没有捕获源时(例如,没有 wf-recorder 的 Wayland):cua-driver recording start <dir>/stop(见 cua-driver 部分),或操作系统录制器(macOS:screencapture -v out.mov)。在这些路径上,没有注释叠加,因此将注释协议保留为文件——一个assertions.md,列出每个setup/test_start/assertion及其结果和近似视频时间戳,与无头路径完全一样。 -
切勿将
--source test(合成模式生成器)作为 UI 证据呈现。它仅用于测试工具链;仓库的tests/test_evidence.py中使用了它。
说明
1. 准备屏幕
- 最大化浏览器/应用窗口;关闭弹出窗口、通知和额外面板。
- 在录制前导航到起始状态(已登录、正确页面),除非设置本身正在测试。
- 记录正在测试的确切版本:
git rev-parse HEAD和git branch --show-current(或部署 URL)——录制器会将它们刻录到报告中。
2. 开始录制
-
在第一个有意义的操作之前开始屏幕录制:
python3 $EVIDENCE start \ --output .artifacts/<task-name> \ --title "<正在验证的内容>" \ --commit "$(git rev-parse HEAD)" --branch "$(git branch --show-current)" \ --environment "<操作系统 / 浏览器 / 显示 / 部署>"它会打印一个包含
session路径和所选source的 JSON;请保留该路径(SESSION=...)用于后续每个命令。源是自动检测的,并捕获整个屏幕;仅当doctor或情况需要时,才传递--source、--geometry、--offset、--display/--xauthority(X11)、--screen-index(macOS)或--output-name(Wayland)。 -
添加一个描述起始上下文的
setup注释:python3 $EVIDENCE annotate "$SESSION" --type setup \ --message "已登录,导航到连接器页面"
3. 通过计算机操作进行测试,边操作边注释
-
在实时应用上通过计算机操作执行每一次交互——录制捕获您的会话,因此测试和证据是同一行为。以可观看的速度工作:每次操作后让 UI 稳定下来,以便状态变化在视频中可见。
-
在每次命名测试开始时,以 Jest 风格添加一个
test_start注释:python3 $EVIDENCE annotate "$SESSION" --type test_start \ --message "当权限为 'always' 时,它应该直接执行工具" -
每次检查后,添加一个带有
--result passed、failed或untested的assertion注释:python3 $EVIDENCE annotate "$SESSION" --type assertion --result passed \ --message "工具运行未出现权限提示" -
断言规则:
- 每个有意义的原语状态变化一个断言——合并,不要为每个 UI 标签注释。
- 使用“前提条件:...”断言来建立起始状态。
- 保持在 80 个字符以下,高信号(录制器拒绝更长的消息)。
- 如果测试无法运行(缺少先决条件、身份验证窗口过期),将其标记为
untested并说明原因——切勿静默跳过。 - 时间戳记录您断言的时间,而不是断言是否正确——在选择
passed之前先查看屏幕。
4. 停止并审查
-
在最终断言后停止录制:
python3 $EVIDENCE stop "$SESSION"这会停止捕获(优雅地,以便录制器刷新;仅在忽略请求时升级),将注释刻录到
evidence.mp4,探测结果,并在旁边写入report.md和manifest.json。成功时打印"verified": true;如果渲染失败,会话标记为finalization_failed——修复报告的原因并再次运行stop(重试不会两次向录制器发送信号)。如果录制器进程无法再安全地发送信号(它已死亡,或其 PID 现在属于另一个进程),则会话标记为recorder_lost。再次运行stop会完成任何已捕获的视频,但前提是确认录制器进程已消失——如果它还活着,请先停止它,否则视频在仍在写入时就会被渲染。 -
在共享之前确认录制捕获了关键时刻:在每个断言时间戳处提取一帧(
ffmpeg -ss <t> -i evidence.mp4 -frames:v 1 frame.png)并检查状态和标签是否可见。 -
填写
report.md的“注意事项”部分;切勿保留占位符。
5. 发布证据
report.md是报告:测试了什么、环境 + 确切提交、每个测试的通过/失败、注意事项。扩展它而不是从头重写。- 将视频 + 摘要作为 PR 评论发布(如果是您的 PR,将其嵌入 PR 描述中)。
gh pr comment无法附加本地视频——通过经过身份验证的浏览器中的 PR 评论框上传evidence.mp4,或将其上传到主机并链接(例如before-and-after上传适配器)。重新打开评论并确认视频播放后再声称已发布。 - 将相同的视频附加到跟踪问题(Linear/Jira),并附带一行结果。
- 将报告 + 录制发送给请求者。
护栏
- 视频必须显示实际实时驱动的测试会话。切勿将脚本化回放、拼接片段或合成镜头作为录制呈现;如果工具箱没有计算机操作工具但存在 GUI,通过
cua-driver驱动;根本没有 GUI 时,改用无头路径。 - 切勿录制半覆盖或平铺的窗口——先最大化。
- 切勿录制显示机密、令牌、客户数据或支付详情的屏幕;如果流程需要它们,标记为
untested并说明原因。 - 验证修复时,显示或引用旧故障以及新成功。
- 始终说明测试所针对的确切提交/分支/部署。
没有计算机操作工具?使用 cua-driver 驱动(有 GUI)
当存在显示器但代理没有内置计算机操作能力时,使用 cua-driver(macOS / Windows / Linux)作为执行器。仍然由您实时测试应用——录制规则不变;仅输入机制不同。
- 在录制前使用
cua-driver doctor验证设置。如果安装了cua-driver技能,请阅读它并遵循其协议——操作前快照的不变量是强制性的。 - 每次交互的循环:
launch_app→get_window_state(可访问性树 + 截图)→ 通过element_token操作(click、type_text、press_key)→verify_state检查预期的后置条件。每个verify_state检查直接对应一个assertion注释。 - 如果
doctor报告capture_ready: yes,继续使用上述捆绑的录制器进行视频和注释;cua-driver 仅提供输入。 - 否则,
cua-driver recording start <output-dir>/cua-driver recording stop是录制器(需要输出目录,并且守护进程必须运行:cua-driver serve)。视频捕获默认启用,并在停止时最终化为<output-dir>/recording.mp4——但在 Windows/Linux 上它会调用 ffmpeg,因此缺少 ffmpeg 或显示器只会产生每轮轨迹文件夹(前后截图、action.json、click.png),没有视频。停止后,在引用之前验证recording.mp4是否存在;如果不存在,修复录制器或根据无头协议将每轮前后截图呈现为编号捕获。 - 如果此路径上没有可用的注释叠加,将协议保留为文件:一个
assertions.md,列出每个test_start/assertion及其结果,与无头路径完全一样。
无头路径(没有 GUI)
当代理没有桌面可录制时,保持相同的断言纪律;将录制器替换为脚本化捕获:
-
将所有内容保存到
.artifacts/<task-name>/(将其添加到 gitignore——证据会被上传,绝不会提交)。将捕获脚本与捕获文件放在一起,以便运行可重复。 -
截图:
before-and-afterCLI(@vercel/before-and-after)捕获 URL 或元素,它的配对直接馈送到 PR 嵌入。在 Chrome 失败并显示“没有可用的沙箱”的容器/VM 中,设置AGENT_BROWSER_ARGS="--no-sandbox"。 -
视频 / 多步骤流程:一次性 Playwright 脚本,运行时不将 playwright 添加到项目依赖中:
npx --yes --package=playwright node record.mjs(单纯的
npx playwright node record.mjs会失败——node不是 Playwright CLI 命令;--package=playwright才将模块添加到路径中。)最小的record.mjs:import { chromium } from "playwright"; const browser = await chromium.launch(); const context = await browser.newContext({ recordVideo: { dir: ".artifacts/<task-name>/" }, }); const page = await context.newPage(); await page.goto("http://localhost:3000/path-under-test"); // ...每步驱动一个有意义的原语状态变化... await context.close(); // 完成 .webm await browser.close();如果文件较大,使用 ffmpeg 裁剪或压缩。
-
注释协议变为文件:按测试顺序编号捕获,在文件名中包含断言——
01-precondition-signed-in.png、02-it-saves-on-blur-passed.png——并在工件文件夹中保留一个assertions.md,列出每个test_start/assertion及其结果(passed/failed/untested+ 原因)。
非 UI 变更仍然需要证据
- API / 性能:带有测量数据的脚本化探测——每个阶段的请求计数、前后延迟——捕获到
probe-output.txt。 - 渲染 / 画布 / 着色器:渲染帧加上像素断言(差异值),通过眼睛检查并保存为 PNG。
- 代理行为:显示工具调用和响应的相关转录摘要。
- Bug 修复:在编写修复代码之前复现并捕获失败——该捕获是前后对中的“前”半部分。
捕获卫生
- 确认您正在探测的服务器运行的是您的代码(正确的端口、正确的进程),尤其在多个代理共享一台机器时:
lsof -i :<port>——或者当没有安装lsof时,`ss -ltnp "spo
...
[已截断以进行翻译]