[P1][CR-T1/T2] 测试有效性:约一半测试文件只测 arena 栈、脚本转测留下 345 处空断言兜底 #535
Loading…
Reference in New Issue
No description provided.
Delete Branch "%!s(<nil>)"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
问题描述
测试套件在数量上很大(545 个文件、6410 个用例),但有两个结构性缺口,导致很多生产路径上的 bug 不会被测试拦住:
?arena=1才会进入的registry/WorldArena栈,而玩家在单机里实际走的鼠标施法入口没有一个测试直接 import。else vitestExpect(true).toBe(true);另有被排除在tsc之外的测试因字段改名变成恒真跳过。证据
T1:测试覆盖与玩家路径错位
按
e475c2e上 545 个*.test.ts的 import 统计:game/skills/registry、skills/impl/*、skills/core、game/engine/{world-arena,missile-engine,combat-pipeline,state-bus,aura-scanner,summon-manager,anim-dispatcher})GameEngine、act-scene或HudManagergame/engine.ts、scene/backend/*、scene/act-scene、ui/hud-manager)src/scene/backend/skill-caster.ts(玩家鼠标施法入口)GameEngine.tick的键盘 /DEMO_SKILLS路径,不经过鼠标施法、WorldRenderer死亡动画门控、药水热键或 HUD 同步。因此 #523 列出的非确定性来源都不会让这条测试失败。tsconfig.json排除的测试因类型漂移静默失效:tests/e2e-drop-parity和tests/fail-fast-drop.test.ts排除在类型检查之外(详见 #534)。if (su.tcNormal) { expect(...).toBe(true) }。但SuperUnique接口(monsters.ts:755-783)的字段名是treasureClass,根本没有tcNormal。tsc之外,编译不报错;运行时su.tcNormal恒为undefined,循环体里的expect一次都没执行,用例绿灯通过。T2:脚本机械转换留下的空断言兜底与遮蔽
13 个
tests/*.test.ts是由scripts/verify-*.ts机械包装而成的,共用同一套模板(例如 collision-orientation.test.ts:31-44、collision-orientation.test.ts:222-267):文件末尾再为每条描述生成一个
test(...):这套模板有四类问题:
else vitestExpect(true).toBe(true)在 9 个文件中出现 345 次(net.test.ts131、items.test.ts58、m4.test.ts56、combat.test.ts38、m5.test.ts33、object-lookup.test.ts14、collision-orientation.test.ts7、tiles.test.ts7、dcc.test.ts1)。用 v8 覆盖率实跑这 9 个文件,有 5 个test(...)走到了else vitestExpect(true).toBe(true)分支(m4.test.ts2 个,dcc.test.ts、items.test.ts、net.test.ts各 1 个)。startsWith只看第一条同名断言:像 collision-orientation.test.ts:128-141、collision-orientation.test.ts:150-212 在 5×5 循环里用同一个前缀调用了 25 次check(...),但末尾的findIndex(x => x.desc.startsWith(...))只检查第 0 次(subX=0, subY=0),其余 24 个子格即使失败也不会被该test()检出,而且这几个文件连vitestExpect(problems).toEqual([])都没有。function __check_disabled(...),文件里没有任何地方调用expect/check。实跑输出是assertions: 0/0 passed,最后靠else vitestExpect(true).toBe(true)(dcc.test.ts:728-733)报了 2 个绿灯用例。即使failures > 0,dcc.test.ts:716-722 里原来的process.exit(1)也被注释成了// disabled exit: 1),suiteCompleted照样设为true。let problems: string[] = [],紧接着if (!isSkip) {里又声明了const problems: string[] = [](以及未被调用的__expect_disabled),把外层同名数组遮蔽掉。根因
WorldArena上,没有补齐玩家实际入口的端到端测试。1a81693),为了让旧的scripts/verify-*.ts快速跑进测试套件,用了脚本批量包壳,并用else vitestExpect(true).toBe(true)掩盖了转换器提取不出断言名字的情况。修复指南
vitestExpect(true).toBe(true):else vitestExpect(true).toBe(true)全部改成vitestExpect.fail(\Missing assertion result: ${expectedDesc}`)`,先让那 5 个空跑的用例暴露出来;startsWith回查_results,而是把脚本里的每个段落直接放进对应的test('...', () => { ... }),直接调用 vitest 的expect(actual).toBe(expected);collision-orientation.test.ts的 25 个子格)放到同一个test()里逐格expect,保证第 1..24 格失败时立刻报错;tests/dcc.test.ts和tests/tiles.test.ts中被改成__check_disabled的断言,并断言failures === 0。tsconfig排除的测试:tsconfig.json对tests/e2e-drop-parity和tests/fail-fast-drop.test.ts的exclude(与 #534 同步);tier1-feature-coverage.test.ts:814的su.tcNormal改为su.treasureClass(并用getTreasureClass?.('normal')覆盖三个难度),同时修掉其余 19 处类型错误。skill-caster.ts+GameEngine+HudManager建一组最小契约测试:鼠标施放各职业代表技能 → 耗蓝、冷却、投射物生成、怪物扣血、掉落与拾取都在同一个权威状态上生效;tests/engine.test.ts之外新增一条覆盖完整单机循环的确定性回归:包含鼠标施法命令、药水消耗、怪物死亡掉落、存档再读档,要求两边每 tick 状态哈希完全一致。验收标准
tests/与src/中vitestExpect(true).toBe(true)与expect(true).toBe(true)的数量为 0;__check_disabled/__expect_disabled/// disabled exit全部清理完毕。tests/dcc.test.ts与tests/tiles.test.ts实跑时真实执行的断言数 > 0,不再打印0/0 passed。tests/collision-orientation.test.ts中故意篡改任意一个非(0,0)子格(例如(4,4))的碰撞位时,测试会失败。tsconfig.json不再exclude任何测试文件,tier1-feature-coverage.test.ts的F17.3对全部 66 个 SuperUnique 都实际执行了expect。npm run typecheck0 error;npx vitest run全部通过。相关
tsconfig.json的exclude。