Skip to content

Verification Methodology

51hhh edited this page Sep 16, 2026 · 1 revision

验证方法论

这一页是本项目最可迁移的部分。它规定「什么算做完了」,适用于任何需要区分「代码写了」和「功能对了」的工程。

核心问题

大量返工的根源是同一件事:把弱证据当成强证据。

「函数存在」「本次运行命中了」「独立复算一致」是三个不同的证据层级,它们不互相替代。一个功能可以同时满足前两条而仍然是错的。

证据分级

等级 含义 典型产物
仅资源或符号 只有文件、字符串、配置或界面存在 目录清单、符号名、截图
仅静态入口 有实现逻辑或部分控制流,缺运行时参数与输出 代码走查、类型契约
单场景运行 在一次具体场景下命中并产出结果 日志、返回值、产物文件
上下文闭合 触发、入口、输入、核心逻辑、调用者、输出消费者、失败路径全部有据,且无剩余关键问题 端到端产物 + 独立复算

保守规则

任一关键字段、失败路径或必要的运行归因缺失,即不评为闭合。

推论:

  • 入口命中若缺场景、参数、返回或输出,只证明该入口在该会话可达,不证明功能正确
  • 负结果只限定到明确场景,不能推广成「该功能不存在」
  • 已纠正的历史错误要单独记录,不要让修正后的条目继续背着旧结论

六条具体判据

这些都是从实际误判里总结出来的。

一、调用成功 ≠ 业务成功

  • 键鼠事件发送成功不等于操作生效
  • UI 控件返回 true 不等于文件真的写出去了
  • 进程存活、界面响应、「已断开」文本,任何单独一条都不足以证明状态正常

验收必须看业务产物,不看中间调用的返回值。

二、跨连接往返不证明另一条连接完成

这条在 X11 大图传输里有具体后果:只做 flush() 而不 check() 实际请求,会让读取方先看到内容、写入抑制被提前消费,同一份数据被重复录入。

三、能力探测与实际执行必须是同一个对象

OCR 引擎候选必须先通过 --version 才被用于识别。否则「探测到了」和「实际调用的」可能是两份不同的程序,用户看到的能力状态与真实行为不一致。

四、成功的判据和失败的判据必须互为反面

dbus.rs 的连接缓存是典型例子:

  • 重连判据是 worth_reconnecting
  • 入缓存判据是 worth_caching
  • 两者必须严格互补

只按「调用成功」决定是否缓存,会把一条被业务错误拒绝但本身完好的连接扔掉,于是每次失败探测都要重新握手。

五、尺寸正确不等于内容正确

这是长截图给出的教训。一张高度完全正确的长图,中间可能少了一整段。

解法是每行唯一编码:给参考内容的每一行画上可解析的行号,成品解码后断言行号严格连续、相邻差全为 1。用尺寸断言永远发现不了漏行。

六、控件渲染图不能充当真实采集证据

控件自己 RenderTargetBitmap 出来的图存在亚像素渲染差异,与合成器实际输出的帧不是同一批像素。实测过一次:直接比较有 36 万个像素不同、RGB MAE 约 2.66。

要验证采集链路,必须拿真实的采集缓冲区做比对。

负控制(tamper fixture)

只测「正确输入产生正确输出」不足以证明门禁有效——一个永远返回 true 的检查也能通过所有正向测试。

因此关键门禁要配套负控制:故意构造被篡改的输入,断言检查必须失败。

本项目里的负控制类型包括:错误的输出路径、无关日志、被篡改的传输内容、被篡改的源文件、被篡改的几何、被篡改的 fixture、非规范的输出位置。

同理,布局测试要有「负控制精确失败」的对照——旧的错误 CSS 必须让 fixture 变红,否则无法确认 fixture 真的在检查那件事。

故障注入

进程与并发相关的代码,正向路径通过没有意义。必须注入:

  • 超时
  • 输入不被消费
  • 输出超量
  • 请求合并竞态
  • 进程回收顺序
  • 分配失败
  • 磁盘写入失败

顺序也要断言:子进程 kill/wait 完成后才释放并发许可,否则许可被提前释放会让下一个请求与正在退出的进程重叠。

竞态验证

异步路径的陈旧响应问题无法靠随机测试稳定复现,要用可控 Promise:显式构造「A 慢 / B 快」两种到达顺序,断言旧响应永远不覆盖新结果。

需要这样处理的路径:搜索、分页、新增/删除事件、预览渲染(图片/尺寸/错误/OCR/延迟库)、翻译、朗读、窗口状态查询。

隔离环境

涉及系统资源的测试必须自建隔离环境,不能用开发者当前桌面:

  • X11 协议测试新建私有 Xvfb,并验证它确实用了私有环境(故意污染父进程的 DISPLAY / XAUTHORITY 后仍通过)
  • fixture 要保持客户端连接以防显示服务器自动 reset
  • 同一测试应在多个独立新建的服务器实例上验证

原生测试默认标记 ignored,只由专用脚本显式运行,避免普通 cargo test 意外访问真实桌面或写入真实剪贴板。

独立复审

作者不能替独立审查签字。 本项目的实践是:实施方提交实现与自测结果,独立审查方另出报告,两者都保留。

独立审查发现的问题单独列表,不混入原始问题清单——否则无法评估原始审查的覆盖率。

失败要保留,不能混为成功

失败记录的价值不低于成功记录。它们防止同一条路被反复重试。

记录失败时要写清边界:

  • 是环境失败还是业务失败(例如一次状态文件的共享读异常属于观察失败,不是被观察对象失败)
  • 修复覆盖到哪一层(例如某个共享读问题在一处修好了,不等于所有同类采集器都已验收)
  • 因果链是否完整(「目标消失」和「某调用导致目标消失」是两个不同强度的结论)

报告纪律

  • 有多少证据说多少话,不把「本次未捕获」写成「未调用」
  • 不用旧摘要否定新的成功证据,也不用少数成功替代全部验收
  • 平台矩阵与安装包构建不能算进「测试通过」的计数
  • 一次成功的手动启动只确认编译、进程和服务可用,不构成交互验收
  • 未完成项一律保留,不写成全部完成

与本项目其它页面的关系

Clone this wiki locally