15 KiB
测试价值与生命周期规范
本文是 AtomUI 测试准入、保留、删除,以及新增功能与 Bug 修复验收的正式规范,适用于开发者和 AI agent。 所有新增功能和 Bug 修复必须遵守;未完成本文规定的临时测试存放、验证、去留判定、清理和交付记录, 不算完成,不得宣称“功能已完成”或“Bug 已修复”,不得标记为 Fixed 或以完成状态结案。
新增功能和 Bug 修复必须完成有效验证,但不要求永久保存验证代码。新建的功能验证、排障和复现测试默认 全部属于临时测试,优先写入临时测试目录,完成验证后删除。全局测试集合默认净新增为 0;长期测试必须证明 其不可替代的独立价值,不以新增测试数量或覆盖率增长作为完成条件。
本文负责测试的去留,以及新增功能和 Bug 修复验收;按改动影响选择验证 负责运行范围、命令 和证据有效性;AI 协作规范 负责根因修复与原始 UX 约束。三者同时生效。 本项目文档或 skill 中“先写失败测试”“补回归测试”“TDD”的一般要求,均指完成修复前后的有效验证, 不得解释为复现代码必须永久入库。明确的长期架构契约按本文保留最小充分保障。
1. 测试分类与默认处置
创建测试前先确定用途;同一文件中混有不同用途时,按测试及断言分别判断,不按文件名整体保留。
| 类型 | 用途 | 默认处置 |
|---|---|---|
| 临时验证测试 | 复现当前 Bug、验证根因、A/B 实验、比较修复方案、一次性迁移检查 | 验证完成后删除,不提交、不进入长期测试集 |
| 常驻契约测试 | 保护仍有效且具有独立价值的产品行为或系统不变量 | 满足准入条件后保留,随契约演进审查 |
| 专项验证 | 真实打包消费、NativeAOT、平台行为、性能基准、压力测试 | 明确触发条件和执行入口,按影响或发布要求运行 |
使用 xUnit、位于 tests/、名称含 Regression 或关联某个 Issue,都不构成长期保留理由。
专项验证仍需证明长期价值,不能作为低价值测试的存放区。类别声明不自动改变现有 runner 的选测范围;
需要调整执行范围时同步维护策略,报告实际执行范围,不能把省略专项后的结果称为完整全量通过。
1.1 临时测试优先(强制)
所有新增功能和 Bug 修复的新增测试,默认先作为临时测试创建。开始写测试前必须先搜索已有测试;已有测试能够 表达同一契约时,直接复用或临时扩展已有测试,禁止再创建一套永久用例。
临时测试按以下顺序选择位置:
- 能独立运行的复现、探针、A/B 实验或功能验证,放在系统临时目录,例如
/private/tmp/atomui-test-<任务标识>/或平台对应的临时目录。 - 必须访问 internal 成员、主题资产、现有 Avalonia Headless 宿主或项目 fixture 时,放在所属测试项目的
tests/<测试项目>/Temporary/<任务标识>/下。文件头必须注明“临时验证,功能或修复完成后删除”。 - 临时测试必须被真实编译、发现和执行。禁止通过
.gitignore、Compile Remove、Skip、改名或不进入测试项目 来制造“已验证”的假象。
默认不得把临时目录加入全局测试选择策略,也不得为了让临时测试看起来正式而新增永久 helper、fixture、资源或
测试项目。需要精确运行时,使用所属项目的直接 filter 或 run --scope iterate --path ... 指向临时测试和目标模块。
功能或修复代码完成后必须立即删除临时测试及其专用辅助产物。优先在最终功能/修复提交前完成删除;如果为了保留 本地红绿证据而在中间提交中包含临时测试,后续必须立即提交删除,并保证准备评审、合并、发布或交付的最终分支 不包含任何临时测试。临时测试不得因“已经提交过”而获得永久保留资格。
2. 常驻测试准入
常驻测试必须同时满足以下四项条件;保留理由写入交付说明,不另建逐用例登记系统:
- 契约明确:指出具体用户行为或系统约束,以及违反它会发生什么错误;“防止回归”不是完整理由。
- 独立检错:能发现编译器、生成器诊断、已有测试或其他确定性检查尚未充分覆盖的真实错误。
- 长期收益:保护核心公共路径、曾反复发生的问题,或后果严重、人工难以发现的问题。
- 成本合理:使用能发现该错误的最低成本验证方式,运行稳定,不锁定与契约无关的实现细节。
新增常驻测试是例外,不是默认结果。除满足以上四项外,还必须在交付记录中同时说明:
- 为什么已有测试、编译器、生成器诊断、ApiCompat、真实打包或专项验证不能覆盖该故障。
- 为什么该契约必须进入每次全局测试,而不能保留为按需专项验证。
- 新用例的运行成本、所属模块和触发范围,以及是否已合并或删除同类重复用例。
缺少任一项说明时,不得将测试从临时目录移入全局测试集合。评审者不得以“有回归测试更安全”、Issue 编号、 覆盖率增长或测试已经写好为由批准永久保留。
不满足准入条件的新验证测试,在本次验证完成后删除。已有测试能保护同一契约时,优先复用或合并, 不为每个 Issue 留下一套重复测试。参数化仅减少维护代码时,不得宣称减少了实际执行成本。
资源泄漏、生命周期竞态、数据错误、AOT/trim 失效、UI 输入与滚动、Semantic Part Style 命中等仍需最小充分保障。 这不意味着每个相关 Bug 的复现代码都要保存:共享机制保留契约测试,具体控件仅保留必要的接线和差异验证。 不可用“临时测试默认删除”撤销尚无其他保障的明确长期契约。
3. 默认不长期保存的测试
- 为定位当前 Bug 编写的探针、状态打印、A/B 实验和修复方案比较。
- 已完成迁移后逐文件检查旧名称、旧方法或旧目录不存在的过程检查。
- 仅固定私有方法名、局部变量名、文件拆分、代码语句写法的检查。
- 固定普通宣传文案、示例数据、元素顺序或非契约性排版数值的检查。
- 触发条件、断言和故障检测能力已被其他测试覆盖的重复测试。
- 已删除功能、失效需求对应的测试。
- 编译器已经可靠保证的类型存在、成员可访问等重复检查。
源码检查不能一概删除。专用 Semantic Part Style 使用要求、主题绑定边界、禁止特定不安全模式等仍有效的 架构约束,可以集中保留检查;判断依据是所保护的约束,而不是是否读取源码。 已知 UI 故障的尺寸、滚动和裁剪条件属于复现条件,不能当作普通排版数值随意删减。
4. 新增功能与 Bug 修复执行流程
- 确认契约与验证范围:新增功能记录新契约和旧实现缺失的行为;Bug 记录原始触发条件、预期和实际结果。 先找已有测试能否表达该契约,能复用则不新增重复测试。
- 建立失败证据:必要时在临时测试目录编写测试,确认新增功能在实现前不满足目标契约,或 Bug 修复前因目标 问题失败。编译环境异常、错误断言或测试未被发现不算有效失败证据。
- 完成根因修复并验证:同一触发条件、同一有效断言在修复后通过。不能通过删除触发条件、放宽断言、Skip、 吞错或重试掩盖失败。修改了复现测试的语义时,重新确认它仍能发现原始故障。
- 决定测试去留:逐项选择删除临时测试、合并至已有测试或晋升为常驻测试。默认删除;保留必须满足第 2 节。
- 清理验证工具:删除本次临时测试及其专用 helper、fixture、资源和临时工程,停止相关进程;同步清理失效映射。
- 验证最终工作树:清理后运行所修改模块的 focused 验证并检查
git diff --check。清理前的旧 receipt 不能 认证清理后的输入;相同最终输入已有有效证据时按 runner 规则复用,不为收尾反复运行。 - 提交交付记录:按第 8 节报告验证证据、测试处置和最终模块结果;满足第 9 节全部门禁后才能宣称功能或修复完成。
确实无法自动化复现时,必须说明技术原因,并记录可复查的手动步骤及修复前后证据。单纯耗时、难写或不想 保留测试不是无法自动化的理由。尚无有效失败证据或未完成原始场景复核时,只能报告验证未完成。 修复前后证据须能对应同一问题及相应源码状态;只保留当前变更范围的简短版本/差异说明,不复制无关源码或日志。
UI 验证必须保留原始尺寸、可见滚动条、嵌套滚动、裁剪、布局和交互条件;自动化通过不能替代必要的原始 UX 复核。NativeAOT、平台和资源生命周期专项义务不因普通单测通过或删除临时测试而消失。
5. 临时测试的存放与清理
- 能独立运行的复现工程按 1.1 节放系统临时目录,引用当前工作区源码,沿用仓库工具链和依赖。
- 需要内部成员、主题资产或现有 Avalonia 环境时,必须优先放入所属测试项目的
Temporary/<任务标识>/目录, 并确认测试实际被构建、发现和执行。 - 本次新增的临时测试在验证完成后直接清理,不需要为了普通清理再次请求许可;不得删改用户或其他任务的文件。
- 清理包括仅被这些测试使用的 helper、数据、fixture、项目引用和进程,不删除仍被常驻测试使用的公共基础设施。
- 不用注释、Skip、永久排除编译、改名或归档代替删除,不建立持续积累的临时测试仓库。
- 默认只在交付说明中保留简短验证证据;需要继续调查的截图或日志记录明确用途和位置。不得长期堆积 TRX、dump、 coverage 等临时产物,也不为保留验证历史而将一次性测试提交后再删除。
临时验证记录只证明本次修复,不等于未来的自动化回归保障;长期保障由保留下来的契约测试和专项验证承担。
6. 存量测试清理
“默认删除”适用于本次新建的临时验证测试。已有测试必须按契约和独立价值审查,不因本次通过、长期未失败 或执行缓慢就直接删除;本规范不授权借当前功能或 Bug 修复无范围限制地删除其他模块测试。
存量删除记录使用以下格式;同类项可以成组说明:
删除对象:具体测试或断言
删除原因:需求已失效 / 仅验证实现写法 / 重复覆盖 / 编译器已保证
保留保障:具体测试或检查;无长期保障需求时写明“不需要”及原因
不要求为了删除低价值测试新增替代测试。删除同时清理失去用途的文件与选测映射,不留下空测试项目或无效 suite。 不得把零测试、gap、skip 或 pending 报告成成功。若清理产生了当前选测工具不能表达的无常驻测试模块,必须先解决 策略/工具的真实覆盖表达,不能临时绕过审计,也不能为了凑数保留无意义测试。
7. 执行成本与运行范围
新常驻测试优先采用纯逻辑验证;需要控件树才使用 UI 环境,需要真实像素才使用渲染验证,需要实际包消费才 启动构建和打包。不得随意关闭 UI 隔离、复用有污染的全局状态或删除原始触发条件换取提速。
- 新增常驻用例热运行超过 1 秒,必须复核成本,说明是否存在更低成本的等价方案。
- 超过 5 秒或包含外部 build/pack/publish 时,必须说明常规运行的必要性,优先作为有明确触发条件的专项验证。
- 阈值是复核线,不是自动删除线。耗时采用正常验证输出,区分构建、宿主启动、初始化和用例执行;不为统计额外跑全量。
- 日常修复只做精确复现和模块 focused 验证。全量只在用户明确要求或发版时执行;不得因临时测试清理自动扩大范围。
- 不以测试数量增长、覆盖率上涨或删除比例为目标;评价独立检错能力、反馈时间、稳定性和维护成本。
具体命令和全量失败处理遵循按改动影响选择验证。
8. 交付记录
每次新增功能和 Bug 修复必须提供以下记录,写在任务交付说明或 PR 描述中即可,不为每项工作新建永久文档:
验证对象:新增功能的目标契约,或原始故障、触发条件与预期行为
实现/修复前:源码状态、执行命令、预期失败及实际结果
实现/修复后:源码状态、执行命令及结果
测试处置:临时测试已删除 / 合并至…… / 保留……;无新增时说明复用了哪些验证
保留理由:仅保留时填写,说明具体契约、独立检错价值、长期收益与成本
清理结果:临时测试、helper、fixture、资源和进程的处置
最终模块验证:最终工作树的命令、范围、通过数量、耗时和结果
专项与 UX:适用检查及结果;不适用时说明,不得遗漏待完成项
手动验证按第 4 节填写步骤与证据,不能伪造测试命令和通过数量。现有缺口、环境限制或待完成专项如实列出。
9. 修复完成门禁(硬约束)
作者交付前必须逐项自查;存在代码审查时,审查者按同一条件验收:
- 有效证明原始故障及根因,完成同一触发条件下的修复前后验证。
- 新增功能证明实现前后的目标契约差异;新增测试已优先放入临时测试目录并被真实执行。
- 完成测试去留判定,常驻测试有满足准入条件的保留理由。
- 本次临时验证测试及专用辅助产物、工程和进程已清理。
- 最终分支的临时测试目录为空;全局测试集合的任何净新增都有不可替代性、全局运行必要性和成本说明。
- 清理后的最终工作树完成对应模块验证,映射有效,无未解决的失败或证据缺口。
- 所有适用的原始 UX、AOT、平台、资源生命周期专项义务已完成。
- 交付记录完整,实际运行范围和验证结果表述准确。
任一项未完成,必须报告“功能或 Bug 修复未完成”及具体缺项,不得以单测全绿、编译成功或代码已改代替验收。 测试数量没有增加、临时复现代码已经删除不构成验收失败;验证缺失、无理由保留临时测试或未清理才构成缺项。
本文定义工程与审查门禁,不表示现有 CLI 已自动判定测试价值或检查全部清理事项。runner 成功仅是执行证据, 作者和审查者仍必须完成上述检查;不得把 CLI 退出码 0 等同于满足全部 Bug 修复要求。