Back to Blog
·1 min read

一条测试记录:「以失败结束,5 个用例已报告,没有点名任何失败」。这种记录我以前…

一条测试记录:「以失败结束,5 个用例已报告,没有点名任何失败」。这种记录我以前会当成"测试挂了"去修断言,现在会先停一下——没有任何用例被点名,意味着断言引擎根本没活到出结论;这

一条测试记录:「以失败结束,5 个用例已报告,没有点名任何失败」。这种记录我以前会当成"测试挂了"去修断言,现在会先停一下——没有任何用例被点名,意味着断言引擎根本没活到出结论;这时去改测试代码,是在修一台还没来得及写报告的机器。

真正的线索在原始输出的错误通道里,不在结论行:stderr 中间夹着反复出现的 CoreData 报错,关键一行 reason 是 "Failed to create file; code = 2"。errno 2 是 ENOENT——要创建的文件路径不存在,最常见的形态是持久化存储的 URL 指向一个从未被创建的目录。App 的启动路径会铺好这个目录;别的宿主(测试宿主)未必走到那段代码,于是第一个真正触发存储初始化的用例一到,进程带着整轮结论一起消失。

为什么平时看不见:

  • 汇总行是给 CI 看的状态,不是诊断。verdict 和原因之间没有连接;而且摘录一旦从头截断,留下的是每条都相同的样板,删掉的恰恰是唯一不同的那一行。
  • 这类"无名失败"最容易被当成 flake 重跑一次了事。重跑通过 ≠ 宿主没病,只说明这次没踩到。

修法,顺序有讲究: 1. 先分类:失败记录里有没有被点名的用例?没有 → 按宿主/环境死亡处理(重跑、查环境),不要去动测试。 2. 再取证:grep 原始 transcript 里的 error / reason 行,而不是读摘要。verdict 行不是证据,执行数和错误通道才是。 3. 再修根因:凡是从自定义路径派生 store URL 的地方,挂载存储前自己保证父目录存在——对每一个会加载存储的宿主都成立,不只是 App 本体;并把"存储打不开"从进程静默死亡改成响亮的、被点名的失败。

一分钟自查:打开最近一次测试日志,grep "Failed to create file" 和 "without a named failure";再看你初始化持久化存储的代码,有没有一行在容器加载之前确保目录存在。没有的话,它只是还没遇到那个会踩爆它的宿主而已。

#build-log

Written by

Peter Zhang

Building local-first Mac & iOS productivity apps at Obelisk Club.