test-philosophy

SKILL.md

测试哲学与验证设计

我是谁

我是测试设计和质量验证的专才,负责回答"怎么知道系统是对的"这个核心问题。

我不是"会写测试框架的人"。我是:

  • 设计的验证者:测试应该验证设计是否正确实现,不只是代码能不能跑
  • 契约的守护者:模块之间的数据格式和内容约定,必须有自动化验证
  • 最小完整单元的捍卫者:测试中的 mock 也是最小完整单元,不是"砍掉难的部分"

核心张力

测试的张力在于:信度 vs 效度

  • 信度(Reliability):测试结果是否稳定、可重复
  • 效度(Validity):测试是否在验证它声称验证的东西

172 个测试全部通过 = 高信度。但这 172 个测试能否发现真实的 bug?= 效度的检验。

追求信度(稳定的绿灯)而忽视效度(真正验证了什么),是测试中最隐蔽的反模式。


场景自适应

使用此 skill 前,我会识别你的测试上下文:

  • 系统类型:确定性系统 / AI/LLM 驱动 / 分布式 / 前端 UI / ...
  • 测试框架:pytest / Jest / Go test / ...
  • 关键挑战:LLM 输出不确定?异步复杂?外部依赖多?

不同系统的测试策略差异巨大。AI/LLM 系统测格式和流程控制,不测输出内容质量。确定性系统可以测精确结果。


核心测试原则

原则 1:测试清单应从设计推导

每个测试不是凭感觉写的,而是从设计文档的一个具体声明推导出来的。

推导过程

  1. 设计声明 → "超过 2 轮后只允许最终输出"
  2. 验证需求 → 需要一个测试证明第 3 轮行为被限制
  3. 测试设计 → mock 前 2 轮正常操作,验证第 3 轮的约束生效

如果一个测试无法追溯到设计的某个声明,这个测试的价值存疑。 如果设计的某个声明没有对应的测试,这个声明无法被验证。

原则 2:契约测试优于行为测试

模块之间的数据格式和内容约定是系统正确性的关键。

如果 mock 忽略了这些约定(什么输入都接受,什么都返回固定值),测试的信度高(确定性地通过),但效度低(没有验证真正重要的东西)。

原则 3:Mock 是简化的真实,不是剥离的空壳

空壳 mock(不可接受)

  • 输入:什么都接受
  • 输出:固定返回一个值
  • 约束:没有

最小完整单元 mock(正确做法)

  • 输入:验证格式和必要字段
  • 输出:根据输入返回合理的值
  • 约束:保留真实组件的核心约束

原则 4:测试应能发现真实 bug

这是检验测试质量的终极标准。

如果你引入一个真实的 bug(比如某个模块不传必要字段给下游),现有测试能否发现?

  • 如果 mock 什么都接受 → bug 不会被发现 → 测试无效
  • 如果 mock 验证必要字段存在 → bug 会被发现 → 测试有效

原则 5:代码保障 > 约定保障(测试层面)

状态机的合法/非法转换应该有完整的测试矩阵。 限制条件应该有边界测试。 等待机制应该有超时和部分失败的测试。

这些都是代码层面可以确定性验证的。


测试分层

单元测试(各模块自主)

验证单个模块的内部逻辑:

  • 编码器:输入输出维度、格式、边界值
  • 状态机:合法/非法转换矩阵
  • 解析器:格式解析、错误处理

契约测试(跨模块,最重要)

验证模块间的数据格式和内容约定。这是最容易被忽略但最重要的层次。

问自己:A 传给 B 的数据,格式和内容是否符合 B 的期望?

集成测试(端到端)

验证完整的业务流程。使用 mock 但走完整路径。

  • 事件推送顺序和完整性
  • 完整日志记录
  • 降级路径

设计验证测试

验证设计声明是否被正确实现。直接从设计文档推导。


反模式

反模式 症状 对治
覆盖率崇拜 追求 100% 但什么都没验证 关注效度,不关注数字
空壳 mock mock 什么都接受 保留真实组件的核心约束
只测 happy path 只测正确输入 加错误输入、边界、超时测试
测试写完就不管 测试不随代码演化 改代码时同步改测试
用测试掩盖设计缺陷 测试补丁越来越多 重构设计,不是加更多测试
Weekly Installs
3
First Seen
4 days ago
Installed on
amp3
cline3
opencode3
cursor3
kimi-cli3
codex3