测试写到一定规模,工具链的信任问题就成了头等大事。这个项目最终积累了 418 条 Hypium 用例(全绿基线),但比用例数量更重要的是围绕执行建立的一套纪律——因为我们很早就被工具链坑过一次狠的。

1. 头号陷阱:Hvigor 的 exit code 会撒谎

把这个坑放在最前面,因为它能悄无声息地废掉你的全部测试:

Hvigor 在 Hypium 断言失败时可能仍返回进程码 0。

也就是说:hvigorw test 跑完,echo $? 是 0,日志里却躺着 failed 的用例。如果你的 CI 或验收脚本靠退出码判断——恭喜,你的红灯永远是绿的,测试烂掉半个月都没人知道(我们就是翻了 Hvigor 日志才发现)。

权威判定必须读测试结果文件:

hvigorw --mode module -p product=default -p module=entry@default test --no-daemon
cat entry/.test/default/intermediates/test/coverage_data/test_result.txt

test_result.txt 里才是真实的通过/失败/忽略计数。我们的所有验收脚本都解析这个文件,退出码只作为参考。这条规则写进了项目交接文档的常用验证区,加粗置顶——工具链的默认信号不可信时,把真相来源写成肌肉记忆

2. 三层区分:构建成功 ≠ 测试执行 ≠ runner 通过

上一个坑的泛化形式,是验收汇报里常见的三种"假绿":

  1. 构建成功:HAP 打出来了。和测试没有任何关系。

  2. 测试编译通过:测试代码编进了测试包。一个用例都没跑也可能是这个状态。

  3. runner 执行且断言通过test_result.txt 里的数字作证。

项目规则要求汇报时严格区分这三层:"测试通过"只能指第三层,且必须给 test_result.txt 的数字(我们的口径:418/0/0 = 通过/失败/忽略)。这个区分的价值在协作:验收方拿到"构建成功"的汇报就知道要打回,而不是默认测试也过了。

3. 用例组织:按模块分文件,命名即索引

418 条用例如果堆在一个文件里就是灾难。测试目录按被测模块一一对应:

entry/src/test/
├── SpeakLabPromptContracts.test.ets      # B14 的 Prompt 契约
├── SpeakLabAsrAdapter.test.ets           # B10 的 ASR 适配层
├── SpeakLabNavigationContract.test.ets   # B04 的导航策略纯函数
├── SpeakLabStreamReleaseGate.test.ets    # B13 的流式时序门
├── SpeakLabAiMemoryCredential.test.ets   # B15 的凭据控制器
├── SpeakLabAnalysisPresentation.test.ets # B06 的呈现投影
└── …

找测试和找被测代码是同一个词。新增模块时测试文件同步创建,这条对称性让"这个模块有没有测试"变成一眼可查的事。

4. 可测性的源头:依赖注入是设计出来的

回看前面几篇,几乎每个模块都有一句"纯函数/可注入":这不是为了优雅,是为了这些模块今天能在 Hypium 里脱离设备被测。例子:

  • ASR 适配层(B10):构造时注入 platform port + 调度器 + 时钟,测试用 fake port 驱动 VAD 完结、错误风暴,断言续接与回调隔离;

  • 生命周期(B12):TrainingFlow 的四个生命周期方法直接调用,断言 ASR release / AI dispose 被触发;

  • 导航策略(B04):纯逻辑栈 SpeakLabLogicalNavStack,导航不变式零 UI 断言;

  • 分词算法(B08):纯函数 + Node oracle 对拍。

模式一句话:难测的副作用(系统 Kit、时钟、IO)全部挤到 port 接口后面,构造期注入。测试不是写完代码再补的事,是写代码时就决定了接口形状。

5. 测试基建的杂项经验

  • --no-daemon:CI/验收环境关 Hvigor 守护进程,避免缓存状态污染结果;

  • SDK 路径DEVECO_SDK_HOME 指到 Contents/sdk(B01 讲过),测试和构建共用这条;

  • hamock@ohos/hamock 在 devDependencies 里备用,但优先用"构造注入 fake"而不是 mock 框架——fake 是显式代码,行为可审查,mock 框架的魔法在排查时常常帮倒忙;

  • 每个阶段任务冻结测试基线数字:418 不是一路随缘涨上来的,每个阶段关单时"累计 X 条、0 失败"是验收项,数字本身被冻结进任务单。

6. 小结

  • Hvigor 断言失败也可能 exit 0;唯一权威是 test_result.txt,验收脚本必须解析它。

  • 汇报三层区分:构建成功 / 测试编译 / runner 通过,互相不能替代。

  • 用例按模块分文件,命名对称;可测性来自构造期依赖注入,不是事后补。

  • 测试基线数字随阶段冻结,成为验收项。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐