← 中文资源

简体中文版本

用随机执行顺序证明测试隔离

以乱序多种子运行套件,找出向外泄露状态的测试,并从源头修掉泄漏。

阅读英文原文

目标

只会在固定顺序下通过的套件,本质是测试之间在 invisibly 共享状态。带种子的乱序执行把“运气好”变成可测试的属性:要么所有顺序都通过,要么某个具体的泄漏有名字、有生产者、有修复。配合消费者开头的“世界必须为空”前置断言,泄漏定位比任何调试器都直接。

步骤要点

  1. 先把两个文件正反两种顺序各跑一遍,一过一挂即证明状态经由共享资源从一个文件泄进另一个。
  2. 用多个种子的全量乱序运行度量影响面,统计各种子的失败数,零失败的种子就是一直掩盖泄漏的幸运顺序。
  3. 用失败种子加文件过滤定位到具体测试,它在该顺序下的前驱就是泄漏生产者,两者都有名有姓。
  4. 给消费者加“世界为空”前置断言:乱序下失败、单独跑通过,把神秘的他者失败变成精确的泄漏探测器。
  5. 在生产者侧补真正的 teardown 或改用每测试独立夹具,随后用失败种子复跑加无种子乱序双验证顺序无关性。

排错提示

每个种子失败点都不一样说明存在多个独立泄漏,从前置断言失败的消费者开始逐个修,每修一个失败面就缩小一圈;全量乱序太慢就改成每晚或每个 PR 跑一次,配合文件级并行把墙钟时间拉平;泄漏源在测试文件之外的单例(模块级缓存、连接池)时,暴露 reset 钩子挂在全局 setup,或按 worker 重新实例化。

适用边界

乱序只证明观测到的顺序下的隔离,罕见交错还需显式并发测试或压力循环;种子含义随 runner 版本变化,登记顺序类 bug 时连同 runner 版本一起记录。

代码示例

# Reverse the usual order -- does it still pass?
npx vitest run tests/auth.test.ts tests/orders.test.ts
# FAILS: orders lists 3 rows, expected 1

# Reproduce with a recorded seed
npx vitest run --sequence.shuffle --sequence.seed=22
# × orders > lists orders for the current tenant

# After fixing the producer teardown
npx vitest run --sequence.shuffle --sequence.seed=22   # all pass
npx vitest run --sequence.shuffle                      # all pass, any order