为什么要写测试
手测一遍点得过来的页面,靠人工就行。可一旦功能多了,每次改一处都要把全流程点一遍,费时还容易漏。自动化测试把验证写成代码,改完跑一遍就知道有没有改坏。
测试的真正价值不是证明代码没错,而是让你敢于重构。
这篇把鸿蒙的单元测试与 UI 测试走一遍。
测试金字塔
测试分三层:底层大量快而细的单元测试,中层少量集成测试,顶层少量慢而贵的端到端 UI 测试。越往下越多、越快、越便宜;越往上越少、越慢、越贵。
测试三层速查
- 单元测试测一个函数或类,快。
- 集成测试测模块间协作。
- UI 测试驱动界面,慢而贵。
单元测试:测纯逻辑
把业务逻辑从界面里抽成纯函数或独立类,对它写断言。输入一组、断言一组预期结果。不碰界面、不碰系统,跑得快。
describe('cart', () => {
it('合计随数量增加', () => {
const c = new Cart()
c.add(10); c.add(20)
expect(c.total).assertEquals(30)
})
})
Given 输入、When 动作、Then 断言,结构清楚。
UI 测试:驱动界面
UI 测试在模拟器或真机上启动应用,按坐标或组件描述找到按钮、点它、断言界面变了。它验证用户真实看到的流程,但跑得慢,只覆盖关键路径。
测试替身与依赖隔离
被测逻辑要连网络、读数据库时,别真去连。用测试替身把外部依赖换成假对象,让测试只关注逻辑本身、且稳定可重复。
覆盖率与 CI 集成
覆盖率看哪些代码被测试跑到了。它是参考不是目标——100% 覆盖不代表没 bug。把测试接进持续集成,每次提交自动跑,挂了就拦下来。
- 先测核心业务逻辑。
- UI 测试只覆盖关键路径。
- 覆盖率辅助,不是圣旨。
实战:给一个计数器写测试
计数器加一次应该加一、上限时不再加。
it('inc 到上限停止', () => {
const c = new Counter(limit = 1)
c.inc(); c.inc()
expect(c.value).assertEquals(1)
})
把边界条件写成测试,以后谁改计数器改坏了,测试立刻报警。质量保障做到这份上,重构才有底气。