关于 principle-test-behavior-not-implementation
Test Behavior, Not Implementation 是一项测试原则,主张围绕调用方或其他用户可观察到的行为编写测试。它通过测试能否发现行为错误、又能否承受内部重构来评估测试。
主要功能
- 01用可观察契约定义行为
- 02检查测试能否发现行为错误
- 03避免依赖内部实现的断言
- 04依据需求推导预期值
- 05在不变量构成契约时测试不变量
适用场景
- 01审查断言内部调用的测试
- 02评估测试能否发现效果遗漏
- 03编写可经受重构的测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ michael-denyer/ pstack-claude --skill principle-test-behavior-not-implementation安装后在 Claude Code 中输入/principle-test-behavior-not-implementation确认已加载。
详细介绍
测试行为,而非实现
测试是对代码如何服务其用户的一项断言:这些用户可能是调用方、最终用户或其他服务。行为是用户通过所用接口能够观察到的内容,包括返回值、错误、可读取的状态,以及对代码外部系统产生的影响,例如发送请求、写入一行数据或发出消息。实现则是用户无法观察到的内容:私有辅助函数、内部调用顺序、中间数据,以及实际完成工作的内部协作者。
用以下两种假设修改来审视每项测试:
- 破坏行为。 让代码返回错误的值、跳过某项操作,或把某项操作执行两次。如果测试仍然通过,它就毫无证明力。常见原因包括:断言比契约宽松、预期值由被测代码计算得出、复述一个从未运行读取该字符串的代码的常量或提示词,以及断言测试自己构造的数据。
- 改变内部实现。 保持所有可观察结果不变,只重构底层代码。如果测试因此失败,它就被实现细节绑住了。每次重构都得重写,而且仍然捕获不到任何 Bug。
保留能捕获第一种修改、且经得住第二种修改的测试。重写或删除其余测试。要同时做到这两点,应通过用户所用的接口驱动代码,并提供具体输入。根据需求而非代码运行结果推导预期值。对契约承诺的内容进行断言,不多不少。
由契约决定测试,而非断言的形式。如果承诺是“空购物车绝不会扣款”,那么断言支付客户端未被调用,就属于对行为的测试。再配上一个确实发生扣款的用例,这样才能证明测试能检测到调用。模拟外部服务收到的载荷属于行为,因为该服务能够观察到它。调用内部辅助函数属于实现,因为用户无法看到。没有记录匹配时,空列表就是精确答案;如果测试只需要某种结果,空列表检查就显得空洞。精确断言错误消息会把测试绑在措辞上,而调用方不会读取措辞。调用方据以分支处理的错误类型才是契约。
测试也可以固定某项不变量,而非某次调用,例如两个表中都必须存在某个键,或某项编译期类型检查。不变量就是行为。如果某个常量值是对用户的承诺,例如文档中说明的默认值,那么固定该常量值就属于对行为的测试;请明确指出这项承诺。