SuperAPI AI 工具集

write-tests

测试与质量

查看项目

更新于 10-15 20:21

技能介绍

用途

这套规范用于指导测试的编写方式,目标是让测试「只在真实行为被破坏时失败」,并且在任何不改变行为的重构或配置修改后仍然通过。它主要适用于新增测试、为修复后的缺陷补写回归测试,以及在审查测试改动时逐项检查。

主要能力与原则

工作流程:逐个编写,而非批量

一次只写一个测试。先写断言,让它在未修改的代码上变红,再让代码实现变绿,从中学习后写下下一个。不要在开头批量编写,因为针对臆想行为批量写出的测试固定的是猜测结果。迭代时使用最快的单文件、单测试运行器,交付前才运行完整套件作为最终关卡。检查退出码而非仅看输出,因为无输出的运行器与绿色通过看起来相同。出现失败时,先读完每一个红色测试再修其中一个,因为它们常共享同一根因。完成前需证明测试可以失败,并走一遍审查清单。

断言什么

断言通过最外层可用入口观察到的行为,包括返回值、退出码、持久化的行、HTTP 响应、渲染输出,而不是哪些内部函数被执行或某个值如何计算。为真正棘手的纯逻辑(解析器、调度器、状态机)保留隔离的单元测试。

不要断言编译器已经保证的内容,例如字段形状或参数类型被拒绝。不要把集合长度当作实际值:在去重、归一化、幂等路径中,长度等于 1 即使归一化已被破坏也会通过,还应断言存储值等于期望的规范形式。

使用能展示该行为的最小规模。先测两个实体加一个机制,再考虑大规模与集成场景。

断言设计契约,而不是当前行为。测试变红时,不要反射性地重新测量并把新数值固定下来;依据明确契约写断言并让代码去满足它。只有契约本身改变时,重新校准才合理。

确定性断言用精确阈值,随机性断言用分布。每次运行都成立的不变量给精确阈值;有噪声或依赖调优的结果(如「A 通常优于 B」「负载均衡得比较均匀」)必须在多次运行或多个种子下以区间断言。单样本固定随机结果不是弱测试,而是盲测试,可能长期掩盖系统性偏差。若必须断言有噪声的差异,放宽边界并在注释中命名为 chaos-marginal。

接缝与 mock

不要把测试耦合到配置,应 mock 接缝。以实时配置值(哪个开关打开、哪个层级是默认)为关键的测试,会在他人合法修改配置时失败。修复方式不是 skipIf 或条件判断,跳过的断言会隐藏耦合并停止覆盖该路径。给函数固定输入,或 stub 查询让固定 id 解析为固定值。试金石是:当配置值改变而没有逻辑变化时,这个测试会失败吗?

不要过度 mock,每个 mock 都是一个冻结的假设。在系统边缘(网络、时钟、文件系统、第三方 SDK、配置查询)mock,而不是内部协作者。stub 内部模块等于硬编码它当前的契约,重构后测试会说谎。当存在可观察结果时,不要把「被调用时传入了什么」当作主要断言。为测试一个函数而 mock 三个内部模块,意味着应向上测一层,让它们保持真实。

测试装置必须像生产环境那样接线。如果某个缺陷只在真实环境下出现,说明装置漏掉了生产环境总会设置的输入,应修装置而不只是修缺陷。

控制变量与探针

一次比较只改变一个变量。固定其他一切:相同的种子、相同的数量、两个分支相同的配置,并禁用不是研究对象的机制。比较测试失败时,先问是否有无关机制泄漏进实验,再动被测代码。

要验证,不要假设。不要对原因(哪条路径触发、失败来自哪里)进行推理后直接行动。写一个一次性探针读取公开状态并打印;看似合理的故事经常是错误的,一个探针能重新定位整个工作方向。探针是草稿:放在无法被提交的位置,问题解答后立即删除,或在其行为值得永久守护时提升为真实测试。

测试运行在他人真实机器上

抓取桌面的套件是人们会停止运行的套件。测试需要什么,就取最不打扰的形式:

  • 绝不抢占焦点。不激活应用、不 makeKeyAndOrderFront、不置顶、不移动指针、不向会话中模拟点击、不播放音频。不应打扰用户的 UI 仍然完全可测:构建窗口、驱动其模型,并对渲染视图断言。需要截图作为证据时,离屏捕获窗口自身图像,而不是拍屏。把激活留在人触发的代码路径上,通过调用处理函数来验证它,而不是反复启动应用。
  • 不要写入用户存放自己状态的位置。每个测试指向临时 home、临时偏好域或 suite、临时安装位置。测试绝不能修改真实配置、资料库、登录项或已安装的应用。生产代码可以读取测试设置的覆盖项;当该覆盖项不存在时必须正常表现。
  • 批量处理不可避免的可见操作。如果检查确实需要真实启动,就在一次运行中完成全部观察,而不是每个断言重启一次,并在证据中说明它是可见的。
  • 不留任何运行中的东西。测试启动的每个进程、窗口、服务器和临时文件都要停止并移除,包括失败时。

证明测试可以失败

从未见过失败的测试是装饰品。对任何回归测试,尤其是修复后写的测试,做一次证伪:回退或破坏生产代码,使其按缺陷方式表现,确认因预期原因变红,恢复后确认变绿。要验证回退确实生效:路径匹配错误的 stash 或 checkout 不会回退任何内容,且「红色」运行会悄悄测试已修复的代码。征兆是:「红色」的数值等于绿色时的数值。

测试在改动后变红时

在编辑任何内容前,按可能性排序分诊:

  1. 测试固化了已删除的语义,它固定的是旧实现的偶然结果,应重新按照契约的真实主张来定义。
  2. 实验失去了对变量的控制,有新的机制泄漏进来,应固定该变量。
  3. 边界过于贴合随机波动,应放宽并注释说明。
  4. 代码确实错了,应探查状态、找到机制。

不要为了让单个测试通过而调常量,却不重跑相邻测试,因为耦合系统会重新洗牌。如果连续两次调整各自弄坏了不同的测试,就停止盲目尝试,说明控制面不对,应找到机制。

审查清单

在任何测试改动上走一遍,同一轮内修复并重跑套件:

  • 断言是否重述了类型保证?→ 删除。
  • 是否会在没有逻辑变化的配置修改下失败,或对配置做了 skipIf 条件判断?→ mock 接缝。
  • 断言是否大多是 mock 内部的「被调用时传入」?→ 向上测一层,针对可观察输出。
  • 是否固定了随机结果的单个样本?→ 断言分布。
  • 是否在去重、归一化路径上只断言计数而没有断言值?→ 补上值断言。
  • 被测函数在生产中是否仍被调用?→ 如果唯一调用者是测试,把函数和测试一起删除。
  • 它能否因正确原因失败?→ 做一次证伪确认。
  • 它是否抢占焦点、移动指针、播放声音,或写入用户真实配置、资料库或应用?→ 改为驱动模型和临时位置,并离屏捕获窗口。

适用场景

适用于新增行为测试、编写回归测试、在代码修改后排查测试失败,以及审查测试差异时。也适用于判断测试是否提供了独立证据。资料中提到,若要判断覆盖率是否增加独立证明、应放在哪里,或哪些现有测试可以删除,可使用 audit-tests。

限制

资料未提供该技能的具体安装方式、命令、支持平台或工具集成信息,暂未提供。