测试质量与必要性
SkillDev tools设计、编写、重构或审查本 TGOSKits 仓库中的自动化测试策略与用例质量时使用。适用于选择单元、集成、契约、系统或 QEMU/板卡测试层级,判断测试是否必要,以及删除或重写重复、脆弱、不稳定、过度替换真实依赖或只追求覆盖率的测试;具体套件发现与运行规则由相应领域技能补充。
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the 测试质量与必要性 skill
What this skill tells your AI
The instructions your AI receives, as published by rcore-os/tgoskits in .agents/skills/test-quality/SKILL.md and read by ahel’s review.
以最少且充分的测试验证完整通用功能的正确性。先找已有功能证明,再决定是否增强;只有缺少独立行为证明时才新增测试。新增配置、参数取值、平台实例或历史问题不自动要求新增测试,测试数量和覆盖率不作为交付目标。
1. 适用方式
任务涉及测试策略、层级选择、回归证明、测试可维护性或低价值测试清理时使用本技能。新增、修改、重构或删除测试也要先经过本技能的必要性门禁。普通实现质量继续遵守 rust-code-quality;本技能负责回答“为什么要测、在哪一层测、现有测试是否值得保留”。
下列语义出现时还要读取对应技能:
- ArceOS Rust QEMU 用例、
qemu-*.toml与输出匹配:arceos-test-adapter; - StarryOS QEMU、板卡、分组系统用例与文件注入:
starry-test-suit; - StarryOS 系统调用与 Linux 用户态可见语义:
starry-syscall-compatibility; - 并发、原子操作、中断、调度和共享状态:
rust-concurrency-safety; unsafe、用户内存、内存映射输入输出、直接内存访问和外部函数接口:rust-unsafe-safety。
用户要求解释方法论、引用书籍或论文,或者质疑某项删测判断时,完整阅读测试质量方法论依据。普通测试实现和审查不需要加载该参考资料。
2. 测试分类
不要只用“单元测试”或“集成测试”描述用例。每项测试都要同时说明目标风险和执行条件,避免同名测试实际拥有完全不同的成本与保真度。
2.1 目标与范围
按测试想证明的风险选择层级。层级不是地位高低,也不由测试框架或源文件目录单独决定。
| 层级 | 主要责任 | 默认不负责证明 |
|---|---|---|
| 单元或组件测试 | 一个可独立理解组件的规则、边界、状态转换和错误处理 | 真实数据库、网络、部署或跨服务协议 |
| 组件集成测试 | 同一应用内多个组件的接口、装配和协作 | 完整用户旅程 |
| 契约测试 | 消费方与提供方对实际使用的请求、响应、消息、版本、错误和幂等语义的共同理解 | 提供方完整业务副作用和完整部署 |
| 系统集成测试 | 本系统与数据库、操作系统、外部服务或硬件的真实边界 | 穷举局部业务规则 |
| 系统或端到端测试 | 完整装配和少数关键用户旅程 | 大量边界组合与细粒度故障定位 |
单元不等于一个函数,也不要求替换所有协作者。集成不等于跨网络;多个真实组件在同一进程内协作也可以是组件集成。系统集成关注一个或多个真实外部边界,端到端测试则从公开入口贯穿完整用户旅程;两者可以重叠,但目标不同。验收测试描述“证明用户需求”的目标,与运行层级正交。
2.2 执行条件
层级确定后,再记录测试的实际环境。执行条件决定速度、稳定性、资源成本以及能够暴露的故障种类。
- 进程内、跨进程或跨机器;
- 单线程、多线程、中断上下文或对称多处理;
- 真实实现、伪实现(fake)、桩件(stub)或模拟对象(mock);
- 是否使用文件系统、数据库、网络、QEMU、实体板卡或外部服务;
- 环境是否由测试独占并负责建立、清理和恢复;
- 预期运行时间、门禁阶段和失败责任边界。
在能真实暴露目标缺陷的前提下,选择反馈最快、环境最稳定、失败最容易定位的层级。低层替身无法证明真实时序、协议或硬件语义时,必须保留对应的集成、QEMU 或板卡证据。
2.3 Rust 测试布局
单元测试验证算法、数据结构和业务逻辑的完整规则,放在对应生产源文件末尾的 #[cfg(test)] mod tests 中。可以访问本模块私有实现,但断言应证明规则正确性,不逐个检查辅助方法、字段或实现步骤。
{crate}/tests/ 放集成测试,以正常依赖方式使用被测软件包,只通过其公开 API 验证完整能力。测试辅助代码只负责准备环境,不重新实现被测功能,也不为测试扩大生产公共接口。
禁止测试通过 #[path] 引入生产源码,也禁止通过 include! 等其他源码包含方式绕过接口边界。需要访问私有算法或业务逻辑时使用源码内单元测试;需要验证公开能力时使用集成测试;依赖真实运行时的功能使用相应系统测试套件。
3. 必要测试设计
一项测试只有在消除明确的不确定性时才具有必要性。新增测试前先完成风险、缺陷敏感度、独特信号、层级与长期成本五项判断。
3.1 必要性门禁
测试设计必须回答下列问题;无法回答时先补充需求、调用链或失败模型,不要直接堆用例。
新增测试前先用一句话说明:在什么输入或操作下,真实实现必须产生什么结果,哪种实现错误会破坏这个结果。无法指出真实实现及其错误后果时,不新增测试;已有用例按第 4 节处置。函数可调用、对象可构造、代码可编译以及执行没有报错,均不能单独作为功能测试的理由。
- 独立行为:它证明哪个完整功能、算法规则或运行时不变量?边界、失败路径和历史缺陷必须归入该行为,不能单凭新增分支或问题编号成为独立用例。
- 缺陷敏感度:删除逻辑、反转条件、破坏返回值或恢复错误实现时,它是否会失败?
- 独特信号:现有测试是否已经以同等或更低成本证明同一风险?
- 最小充分层级:更小测试能否保持同等真实性;更大环境是否确实增加了协议、装配、时序或硬件证据?
- 长期收益:运行、诊断和维护成本是否与风险重要度相称?
为风险记录严重度、发生可能性或历史频率、负责所有权以及已有保护,再决定测试数量和门禁顺序。高损失、易发生、曾回归、频繁修改或跨所有权边界的行为优先测试。代码行数和实现复杂度只能作为风险线索,不能替代契约与故障分析。
3.2 有效判定
测试必须包含能够区分正确与错误实现的判定标准。只执行代码、只证明没有崩溃或只命中成功输出,不足以证明功能正确,除非测试职责明确就是启动探针。
断言应落在本项目负责的行为上。构造后回读传入字段、调用无逻辑访问器、检查默认值、逐步确认测试准备状态,不形成独立行为证明。准备步骤可以保留必要的失败诊断,但不要拆成独立用例;仅删除其中的格式断言,也不能使剩余的构造与字段回读成为必要测试。
使用替身时,确认输入确实经过生产逻辑,最终断言能识别生产逻辑的错误。测试自行实现存储、状态转换或错误返回,再验证该替身按自己的实现工作,属于替身自测。替身应只提供触发真实规则所需的环境;若移除被测生产逻辑后用例仍会通过,应重新划定测试边界或删除。
- 断言可观察结果、错误、状态变化、持久化结果或必要协议交互;
- 覆盖成功路径、关键边界和有实际后果的失败路径;
- 修复错误时优先复用或增强已有功能测试,只有缺少独立行为证明时才新增;按
AGENTS.md验证同一测试在错误实现上必然失败、修复后通过; - 新行为可以通过实现前失败、临时恢复旧实现、变异测试(mutation testing)或故障注入核对缺陷敏感度;
- 成功和失败匹配必须传播到最外层运行器,不能只打印文本后以零状态退出。
错误修复的确定性红绿证明是项目要求;变异测试和额外故障注入只在风险、工具与成本相称时使用,不能拿来替代真实回归。测试代码也可能包含错误。复杂控制流、隐藏输入、过宽断言和错误的模拟对象预期都会制造“产品错误但测试仍绿”的静默遗漏。
3.3 稳定与诊断
相同代码、输入和受控环境应产生相同结果。测试失败时,应能快速区分产品错误、测试错误和环境错误。
- 测试自行建立和清理状态,不依赖执行顺序或其他用例残留;
- 控制时间、随机数、标识符和资源分配,等待具体事件或条件,不使用任意
sleep代替同步; - 避免共享数据库、实时外部服务和不可恢复的持久状态进入提交门禁;
- 名称表达场景和结果,输入、动作与断言保持完整、简洁并靠近;
- 隔离不稳定测试(flaky test)只能作为限期止损,必须有负责人和根因修复,不得用无限重跑维持绿色状态。
随机、性能、压力和混沌测试可以使用统计判定,但应与确定性回归门禁分开,并明确样本、阈值、误报处理和失败解释。
3.4 通用规则与具体实例
测试按完整行为规则组织,不按配置、参数、平台、软件包、问题编号或测例清单逐项组织。新增使用既有规则的实例不新增测试;行为改变时先检查能否复用或增强现有功能证明,只有缺少独立行为证明时才新增。将逐项用例改成遍历真实清单的参数表,并不能消除对清单的重复维护。
删除独立的参数回读、默认值复述、配置名称与数量锁定、生产清单镜像及无独立功能意义的组合枚举。非法输入的拒绝、错误传播、状态保持和资源回收应通过完整操作验证,并入所属功能;不按每个参数或错误码机械拆测。解析、校验本身是公开能力时,从其入口验证接受、拒绝及约定的后果,不只回读输入或调用私有校验辅助函数。
验证解析、发现、筛选、优先级、执行计划和失败汇总时,优先使用自包含的最小配置、临时目录及合成名称,并调用真实实现。样例应代表等价类或边界,预期结果来自被保护的规则;不要读取当前生产清单,再逐项固定其名称、默认值、数量或组合。通用测试仍需要具体输入,“通用”不意味着去掉具体值或弱化断言。
判断实例是否只是样例,可以尝试替换其名称、路径及无关配置:保持同一规则后,测试仍应成立。具体数值可以代表等价类或必要边界,不要求引入随机生成或属性测试框架;不同取值触发相同规则时不新增用例,也不把无关功能合成难以诊断的巨大用例。真实部署配置的兼容性或装配验证应放在相应集成边界,验证实际能力;特定应用、脚本或测例自身的功能回归由其所属测试套件负责,共享工具测试负责通用执行机制与失败传播。
清理时删除重复的实例检查,将仍有价值但依赖生产清单的机制测试改为合成样例。仅改名或把专用断言搬进通用名称的函数,不算泛化。历史回归若包含独特失败信号,应保留最小触发条件或移到实际责任边界,不能因名称含平台或配置就删除。
3.5 运行可信度
测试发现、零测试拒绝、失败传播、LTP 完成判定和架构执行要求负责证明选中的功能确实运行。运行器的 --test-case 选择器、固定 feature profile、成功标记及上游完成数量不是新增固定实例断言的理由,也不能因包含固定值而撤销。测试去重与运行矩阵去重分别判断,不能以缩减测试数量为由漏跑必需目标。
4. 不必要测试审计
不必要测试不是“长期没有失败的测试”,而是没有独特风险信号,或者其信号不值得持续成本的测试。审计时为每项用例给出 保留、重写、下移、移出门禁 或 删除 结论。
4.1 默认删除或重写
下表是低价值测试的默认处置。使用“合理例外”时必须同时指出可观察契约、能够让测试失败的错误实现,以及更低成本测试不能提供的证据;不能用“可能有用”保留无边界测试。
| 测试形态 | 默认处置 | 合理例外 |
|---|---|---|
| 只断言私有字段、辅助函数或内部调用顺序 | 改为从公共边界验证行为;无外部价值时删除 | 调用顺序本身是事务、协议或安全契约 |
| 为每个生产方法机械建立对应测试 | 按行为、边界和状态转换重组 | 独立公共函数本身就是完整契约 |
| 高层测试复述低层完全相同的输入、行为和判定 | 删除高成本重复项或下移 | 高层额外证明部署、协议、资源或真实时序 |
| 复述标准库、框架或第三方库自身行为 | 删除,改测本项目的配置、适配和错误映射 | 项目承诺特定版本兼容或包装契约 |
| 没有断言、断言恒真或只检查覆盖率 | 补有效判定;没有目标风险时删除 | 明确标注的启动或存活探针 |
| 只验证模拟对象调用次数而不执行真实逻辑 | 改用真实轻量实现或伪实现,并补真实集成证据 | 超时、故障注入或交互本身就是契约 |
| 替换全部协作者后声称证明完整功能 | 重新划定组件边界或上移到真实集成 | 严格隔离算法或故障传播边界 |
| 巨大、不可审阅或每次盲目更新的快照(snapshot) | 拆分并显式断言关键语义 | 稳定、短小、确定且逐项审查的输出契约 |
依赖任意 sleep、生产网络或共享数据库 | 改为条件同步和隔离环境;无法归因时移出门禁 | 独立生产探测,不冒充提交回归 |
| 长期不稳定且失败只能靠重跑消失 | 限期修复;无诊断价值且不可修复时删除 | 独立统计测试并使用专用判定 |
| 只为覆盖率触达代码但不能识别错误 | 删除或补充真实行为判定 | 覆盖率只用于发现盲区和趋势 |
| 对应功能、调用者或兼容责任已经消失 | 确认所有权后删除 | 旧协议、数据迁移或长期支持版本仍受承诺 |
| 构造对象后回读字段、默认值,或只验证类型可用 | 删除独立用例,由实际使用行为覆盖 | 校验、资源取得及兼容责任通过完整功能验证,不保留独立回读用例 |
| 逐项验证中间表示、准备步骤或阶段状态 | 合并到有最终判定的功能用例;没有独立风险时删除 | 中间状态本身可被消费者观察,或构成提交、回滚、发布等契约 |
| 枚举参数组合、常量或展示文本,但没有项目规则 | 删除机械枚举;拒绝、转换或协议行为并入完整功能验证 | 文本、布局属于外部协议时,从消费者边界验证协议结果 |
| 每增加一个配置、平台、软件包或测例,就增加固定该实例内容的测试 | 删除实例清单复刻,按第 3.4 节验证通用规则 | 独立兼容或历史失败行为在实际责任边界验证,不固定实例内容 |
| 逐项测试无逻辑的访问器(getter、setter)或转发 | 删除或由调用者行为自然覆盖 | 其中包含权限、转换、缓存或其他契约 |
| 自动生成但无人能解释风险和判定的测试 | 人工筛选和重写,其余删除 | 生成器用于探索,保留结果已经人工确认 |
测试产生了沉没成本不是保留理由。删除前核对公共消费者、历史缺陷、兼容版本和发布门禁,避免把低频但高损失的保护误判为冗余。统计、性能、压力、混沌、生产探测或必须依赖实时外部系统的测试可以移出提交门禁,改为独立定时或发布阶段运行;移动后仍要保留负责人、阈值、失败处置和结果追踪。
按整个用例重新判断价值,不以减少几条断言代替清理。删除用例后检查专属替身、辅助函数、空模块、依赖和发现入口是否仍有消费者,并清理失去用途的部分。参数化、格式校验、状态转换和替身只是测试手段;是否保留取决于真实契约及独特的错误信号,不按名称或语法形式一刀切。
4.2 跨层去重
代码覆盖重叠不等于测试重复。低层规则测试、真实数据库约束测试和关键端到端旅程即使执行相同行,也可能分别保护不同风险。
只有同时满足下列条件才按重复测试处理:
- 输入、行为和判定实质相同;
- 能发现的故障种类相同;
- 更高层没有增加真实装配、契约、并发、硬件或部署证据;
- 删除后不损失更快的定位信号、外部兼容保证或独立所有权门禁。
优先保留最低成本的充分证明。上层只保留低层无法证明的连通性、兼容性和关键旅程,不用浏览器、完整内核或实体板卡穷举局部输入组合。
5. 常见分层
下面的例子用于校准层级,不是固定模板。实际测试仍应从目标风险和运行边界出发。
| 对象 | 低层责任 | 真实集成责任 | 默认不保留的高成本重复 |
|---|---|---|---|
| 解析器 | 公开解析接口的等价类、边界、非法输入和状态转换 | 真实读取器、编码、分块输入和配置加载 | 在每层重复完整语法样本,或直接测私有词法分析辅助函数 |
| 数据库访问层 | 领域规则、权限、错误映射和状态变化 | 生产同类数据库的迁移、约束、事务、并发和回滚 | 模拟整条对象关系映射调用链后只验证 save() 次数 |
| HTTP 服务 | 参数规则、业务错误和状态转换 | 路由、中间件、序列化、认证、契约、真实数据库或外部服务 | 通过浏览器穷举本可在组件层证明的所有非法参数 |
涉及真实调度、阻塞唤醒、核间中断、中断请求、计时器、对称多处理、亲和性、上下文切换、系统调用或硬件寄存器语义时,宿主伪运行时只能验证纯模型,不能代替 QEMU 或板卡证据。纯算法、队列和状态机模型仍可保留为独特的低成本信号,但名称和文档不得声称已经证明真实运行时。
6. 交付要求
设计测试时,把结论写成“风险、层级、环境、判定、失败证明、与现有测试的关系”。审查测试时,明确给出保留、重写、下移、移出门禁或删除结论,并说明风险与成本依据。
不得为了让门禁通过而削弱断言、扩大成功正则、丢弃独特的确定性回归证明、增加无限重试或把真实失败改成跳过。按本技能删除冗余用例或将回归并入通用功能测试时,核对原有独特失败信号仍被保留。验证命令与运行证据遵守仓库 AGENTS.md 及命中的领域技能;本技能不复制各测试套件的发现和运行细节。
Signals
- GitHub stars
- 67
- Forks
- 133
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
test-quality-rcore-os- Source
- github.com/rcore-os/tgoskits