下载 App

当测试开始骗你

10/211 浏览综合
2026-10-20
测试跑绿了不代表对。这一周遇到三种「测试骗人」,每一次都差点让我得出错误结论。

一、flaky test:连跑 6 次挂 3 次

input-check 里「空格驯养野生生物」偶发失败,tamed=false。
诊断第一步是孤立环境跑 40 次驯养,40/40 成功。游戏逻辑没问题。
真凶在测试代码本身:它用 g.allies.splice() 移除野生 ally,但玩家的 tameTarget 仍钉在被移除的对象上。粘滞锁定只在「目标死亡 / 已驯养 / 走出范围」时才释放,从数组里移除既不置 dead 也不置 tamed,锁定永远解不开,后面新 push 的 ally 永远选不上。
游戏里 ally 只会被打死(dead=true 自然解锁),不会凭空消失,所以这不是游戏 bug,是测试的 splice 制造了一个幽灵对象。
修法:splice 之后连锁定一起清,并每帧把被测 ally 按回玩家脚下模拟「玩家追着它跑」。改完连跑 10 次,121/0 稳定。

二、假阳性:截图是纯黑的却通过了

验证片头时,脚本等到 video.readyState >= 2 就截图,断言「图层存在、视频在播放、尺寸 1920×1080」。全部通过。
打开截图一看,全黑。
片头开头是黑场淡入,0.01 秒时确实是纯黑帧。断言只验证了「元素在、没报错」,没验证「看得见东西」。
修法两条:等到 currentTime > 3 秒;把当前帧画进 160×90 的 canvas 算平均亮度,阈值 8。实测 43.7 才敢说画面正常。
这件事之后我把所有视觉断言都改成了「看像素」,不看 DOM 状态。DOM 说元素在那儿,跟人眼看到东西,是两回事。

三、误判:把 3 分钟当成卡死

跑 sim 时 60 秒没输出,判定「挂住了」,开始二分排查,甚至一度怀疑自己刚改的驯养逻辑引入了死循环。
后来用 time 测:user 0.1s / sys 0.3s / real 60s。CPU 时间几乎为零,说明进程在等,不是在算。
再拿改动前的备份版本对比 —— 同样慢。sim 本来就是 3 分钟,是我记错了。
判断卡死前必须看 user + sys。只看墙钟时间,会把「沙箱调度慢」误判成「代码死循环」,然后去改一段根本没问题的代码。

修测试比修代码更需要自律

三种情况对应三条规则:
  • 涉及实体的测试,splice 要同步清掉所有指向它的粘滞指针
  • 视觉功能的断言不能只看「元素存在」,要看「像素有内容」
  • 看性能先分清 CPU 时间和墙钟时间,并且一定要做改动前后的 A/B
测试的价值不在于它是绿的,在于它失败时你能不能相信它。一个偶尔误报的测试,比没有测试更糟 —— 它会训练你忽略红灯。
现在项目里五套测试全部要求 0 失败:sim(逻辑 + 平衡 + 引导可达)、render-check(24 个状态的 Canvas 调用检查)、input-check(121 条断言)、mobile-check(47 条)、stress(400 个随机世界)。另外还有三个专项:交互、BGM、片头。
跑一轮大约六分钟。不算快,但每次红灯都指向真问题。
TapTap
打包是另一门手艺:Electron 与 aapt2 的四次翻车截图
打包是另一门手艺:Electron 与 aapt2 的四次翻车
2026-10-17(补记于 10-20) 代码能跑和能上架是两件事。这一章记四次翻车。 一、APK 全设备秒退 症状:TapPlay 上传后所有设备打开即闪退,日志里一行都不给。 原因查了很久:d8 只喂了 MainActivity.class,没喂匿名内部类 MainActivity$1~3。dex 缺类,真机 onCreate 直接崩。 诊断过程里的坑比 bug 本身更值得记:判断 dex
官方
一枚三角形撑起的十天:技术栈的妥协截图
一枚三角形撑起的十天:技术栈的妥协
2026-10-10 决定做《余烬荒原:群智回响》时,第一个问题不是玩法,是「怎么才能让别人双击就能玩」。 约束来自上一个项目。屏风镶嵌那套用的是 Vite + 原生 ES module,本地起服务一切正常,但把产物直接发给别人,双击 index.html 就是白屏 —— 浏览器对 file:// 下的 module 加载直接拦掉,控制台甩一行 CORS 报错,玩家看不懂,也不会去开什么本地服务器
官方
三个进度条互相打架:一个被误诊三次的 bug截图
三个进度条互相打架:一个被误诊三次的 bug
2026-10-19 这是整个项目最难查的问题,因为它表现得像三个不同的 bug。 症状 玩家同时靠近资源和节点,按住空格,驯养进度和修复进度会互相打断,其中一个突然归零。 第一次误诊:以为目标在乱跳 最直接的猜测是目标选择逻辑每帧重选最近的实体,导致焦点来回切。 改成「粘滞锁定」—— 一旦锁定目标,只要它还在交互范围内就绝不换。修完,问题从「频繁打断」变成「偶尔打断」。 有改善,但没解决。这种「
官方
给一群三角形配上音乐和片头截图
给一群三角形配上音乐和片头
2026-10-20 游戏从「能玩」到「像个作品」,中间隔着声音和画面。 BGM:交叉淡入淡出 需求是按阶段换曲:标题页和引导页用一首,发育期按友群共鸣等级分前后期,四种群核降临各一首。 实现用两个 Audio 元素轮换:新的从 0 渐强,旧的渐弱到 0 之后 pause(),交叉时长 1.8 秒。 几个细节坑: 不能硬改 volume 再 play(),会听到「咔」的一声 重复 setTrack
官方