《鸿蒙测试入门:单元测试与 Profiler》
要点
鸿蒙的官方测试框架叫 Hypium,DevEco Studio 5.0 开箱即带:单元测试走 ArkTS 的 describe/it/expect,用例跑在本地模拟器或真机上。这篇做三件事——写第一条单元测试、在本地模拟器跑绿、用 Profiler 看清性能面,末尾给一份验收清单。
本文不做:ArkUI 的 UI 测试框架细节(arkuitest 一句带过)、云测试平台与上架自动化、性能调优的完整方法论——Profiler 只讲”看得见什么、怎么定性”。工程与业务代码的来历在鸿蒙实战篇,本文的测试直接往那个工程上叠加。
写第一条用例
工程向导默认生成两个测试目录:src/test 是本地单元测试,src/ohosTest 是跑在设备或模拟器上的测试(含 UI 测试)。纯逻辑先写 src/test。Hypium 的样子:
import { describe, it, expect } from '@ohos/hypium';
import { calculateTotal } from '../main/ets/util/Price';
export default function priceTest() {
describe('priceTest', () => {
it('单价乘数量', 0, () => {
let total = calculateTotal(99, 3);
expect(total).assertEqual(297);
});
it('非法输入抛错', 0, () => {
let err = false;
try {
calculateTotal(-1, 1);
} catch (e) {
err = true;
}
expect(err).assertTrue();
});
});
}
几个 ArkTS 特有的地方值得点名:it 的第二个参数是超时毫秒数,必写,0 表示不限时(真有异步逻辑时写具体数字,比如 3000);断言不是 expect(x).toBe(y),而是 assertEqual / assertLarger / assertTrue 这一族,从 Jest 迁过来要换手指记忆;文件导出的函数要在 List.test.ets 里注册才会被发现——注册这一步是 Hypium 和主流框架差异最大的地方,漏了注册的测试文件就是不存在,没有任何报错提示你。
预期输出:DevEco 右侧测试面板里该用例变绿,日志出现 pass 数。环境要先”撞”一次——故意把 assertEqual(297) 改成 296 跑一遍看红、看失败断言的报错长什么样,再改回来。见过一次红色的样子,后面排查心里有底。
边界值先补齐
以 calculateTotal 为例,第一条正常用例之外,值得占位的三个边界:
- 数量为 0:断言返回 0 而不是抛错——业务上”买 0 件”是合法输入;
- 单价为负:断言抛错——价格模块不该静默接受负数;
- 极大数量:断言结果不溢出(ArkTS number 口径)或按业务定义封顶。
三条写完,这个工具函数一共 5 条用例,覆盖了它全部的公开行为。多数工具类的天花板就在 10 条以内,写到”每个分支有一条用例”就该停手,别为凑数制造重复用例——重复用例在重构时是纯负担。
异步用例怎么写
it 的回调可以是 async,里面正常 await,框架会等 Promise 落定;超时参数这时候才真正起作用——异步链路卡死时用例按这个时间失败,而不是挂住整个 run:
it('异步计算完成', 3000, async () => {
let result = await computeAsync(21);
expect(result).assertEqual(42);
});
夹具方面,describe 里可以配 beforeEach / afterEach,每个用例前重置共享状态。我的习惯是干脆不共享:每个用例自建数据,Hypium 的用例执行顺序按注册顺序来,共享可变状态会让调换注册顺序后结果改变——这本身就是一种坏味道。
从 Jest 迁过来的对照
从 Web 前端转来做鸿蒙的人,骨架不用重学,对应关系五条:
- describe / it 结构一致,只是 it 多一个必写的超时参数;
- expect(x).toBe(y) → expect(x).assertEqual(y);
- expect(x).toBeTruthy() → expect(x).assertTrue();
- beforeEach / afterEach 同名可用;
- jest.mock 没有等价物——ArkTS 没有运行时模块替换,替身要靠构造参数注入。
最后一条影响最大:没有模块级 mock,意味着”顺手 mock 掉一个 import”的写法不存在,依赖必须显式传参。举个最小的注入例子:页面需要”读用户设置”,把读取动作做成构造参数传进状态管理类——本地单测传一个返回固定值的替身,模拟器上传真实现,同一段业务代码两种环境各跑各的。这在工程上是好事,测试逼着代码把依赖关系摆到明面上。
本地模拟器跑测
路径一,IDE:测试用例左边的 gutter 绿箭头点下去,DevEco 会自动启动已配置的本地模拟器、安装测试包、跑完把结果回显到 Test Log 面板。第一次跑要等模拟器冷启动,后面就快了。本地模拟器跑测试不需要签名证书,这点比真机省事。
路径二,命令行。工程根目录:
hvigorw test # 本地测试
hvigorw onDeviceTest # 跑在设备/模拟器上,API 12 起支持,也用于覆盖率
前提一样:Device Manager 里的本地模拟器已创建并能启动。验收标准:模拟器上用例绿,且 Test Log 能翻到每条 it 的通过记录,两条都要满足。
哪些逻辑适合放 src/test:价格计算、日期格式化、状态机、数据映射这类纯 ArkTS。凡是 import 了设备能力的(网络、存储、UI 上下文),本地单测跑不起来——挪到 ohosTest 上模拟器跑,或者把设备依赖做成参数、测试里传替身。上不了的设备能力先别硬测,UI 交互交给预览器手测,这是当前工具链下最诚实的分工:预览器保外观,单测保逻辑,Profiler 保性能,三件工具各管一段,谁也不替代谁。
Profiler:性能看得见
操作路径:连上模拟器或真机,底部工具栏点开 Profiler,选会话类型(Time / CPU / Memory / FrameRate 都可单独起一个会话),点录制后回到应用里正常操作,操作完停止,等分析图渲染出来。第一次用别贪多,一次只开一个会话,图能对齐时间轴就够用。
常看三张图:
- CPU:各线程占用曲线,先看主线程有没有长块被卡住;
- Memory:ArkTS 堆与原生内存曲线,看有没有只涨不跌的段;
- FrameRate / Time:帧耗时分位,找掉帧发生的时间点。
定性用法三条:启动慢,进 Time 视图看 ability 首帧前的耗时块,找最大的那块下手;滑动卡,FrameRate 视图里找超时长帧,回 Time 视图对齐时间点,看主线程那段在干什么;疑似泄漏,反复进出同一页面十次,Memory 曲线阶梯只升不降就是嫌疑对象,用堆快照对比对象数确认。
口径提醒:模拟器的性能不代表真机。定性结论(哪个函数占大头、内存是否泄漏)可用;绝对毫秒数别当真,任何写进文档的数字都要真机复测。更深的 HiTrace、HiAppEvent 打点不在这篇范围。
一次完整排查的动线
把三张图串起来用。假设现象是”列表滑动发涩”:先录 FrameRate,找到掉帧集中的时间点;切到 Time 视图对齐同一时段,看主线程那几帧在执行什么——答案往往就在那几十毫秒的调用栈里;如果栈里是列表项构建时的一次同步 JSON 解析,把解析挪到数据加载阶段或后台线程,再录一遍,对比曲线走势是否平滑。整个过程产出的是”哪段代码在占主线程”的定性结论,具体优化手段(缓存、懒加载、移出主线程)不属本文范围,但定位到”哪一段”已经完成了排查的大半。
常见坑
- 测试文件没被跑:忘了在 List.test.ets 里注册导出的函数。现象是面板里压根不出现这个 describe,先查注册再怀疑别的。
- it 忘写超时参数:直接编译不过,这是 Hypium 的硬约束,别嫌它烦。
- 本地测了设备能力:import 了 @ohos 网络或存储模块,本地单测直接失败。按”纯逻辑进 src/test、设备相关进 ohosTest”分流。
- 断言用了 Jest 语法:toBe、toEqual 都不存在,编译期就会报,改 assertEqual 族。
- 把模拟器帧率当真机结论:模拟器渲染走的是宿主机,帧率数字系统性偏高,只能定性不能定量。
验收清单
- src/test 至少 3 条用例:一个正常路径、一个异常路径、一个边界值(0、负数、空字符串任选),IDE 面板全绿。
- 至少一条异步用例带明确超时参数,跑绿。
- hvigorw onDeviceTest 在本地模拟器跑完,报告里可见全部用例。
- 用例之间无共享可变状态:把 List.test.ets 里的注册顺序调换,结果不变。
- Profiler 完成”启动—滑动—反复进出页面”三段录制,每段能指出最大的一块耗时在哪。
- 测试目录 grep 不到 Thread.sleep 和裸的定时器等待。
学习顺序上,测试是”实战之后”的第一站:先把实战篇的应用跑起来,再拿它的工具类补单测;整个鸿蒙系列怎么排布、测试之后该进阶什么,看鸿蒙学习路线的对应阶段;写用例时被 ArkTS 语法卡住,回ArkTS 语法要点补对应条目。
本文数据核对时间:2025-02-24:HarmonyOS NEXT 5.0(2024-10-22 商用发布,开发者套件 5.0.0 Release 于 2024-11 推送)+ API 12 + DevEco Studio 5.0.0;@ohos/hypium 为官方单元测试框架,hvigorw 命令口径以华为开发者文档为准。