鸿蒙自动化测试高级体系:单元测试/XTS用例/UI自动化测试/性能压力测试/Monkey测试全栈落地
·


一、前置思考
1.1 为什么测试是发版的底气?
没有测试体系的上线:
→ 全凭人肉回归 → 漏测是常态 → 线上事故靠运气
测试金字塔:
┌─────────┐
│ E2E │ 少量: 关键路径端到端
├─────────┤
│ UI │ 中量: 界面交互自动化
├─────────┤
│ Unit │ 大量: 逻辑单元测试
└─────────┘
底层越厚,质量越稳
1.2 测试体系的四层能力
单元测试: 函数/类逻辑验证 (快、多、便宜)
XTS 用例: 系统兼容性/接口契约验证
UI 自动化: 界面交互模拟用户操作
性能/压力: 性能指标 + 极限负载验证
Monkey: 随机操作找崩溃/卡死
二、核心原理
2.1 单元测试框架
基于 JUnit 风格的 ohosTest / test 目录:
测试文件结构:
entry/src/test/ # 单元测试 (本地)
entry/src/ohosTest/ # 集成测试 (设备)
用例注解:
@BeforeAll / @AfterAll: 类级前后置
@Before / @After: 用例级前后置
@Test: 测试用例
断言:
expect(actual).assertEqual(expected)
expect(actual).assertTrue()
expect(actual).assertInstanceOf(Type)
2.2 XTS 兼容性测试
XTS (X Test Suite): OpenHarmony 兼容性测试套件
→ 验证设备/系统是否符合兼容性规范
测试类型:
ACTS: 应用兼容性测试 (接口/行为)
HATS: 硬件兼容性测试
DCTS: 分布式兼容性测试
价值:
→ 设备认证: 通过 XTS 才能打 Compatible 标
→ 接口契约: 防止 API 行为回归
→ 生态保障: 应用跨设备行为一致
2.3 UI 自动化测试
基于 UI 控件树的自动化:
模拟用户操作:
driver.findComponent(by.id('btn_login'))
driver.click(component)
driver.inputText(component, 'user@example.com')
driver.swipe(...)
断言 UI 状态:
expect(component.isVisible()).assertTrue()
expect(component.getText()).assertEqual('登录成功')
适用:
→ 核心流程回归 (登录/下单/支付)
→ 多设备一致性验证
→ 发版前冒烟测试
2.4 性能与压力测试
性能测试:
→ 启动耗时 / 帧率 / 内存 / 功耗
→ SmartPerf / DevEco Profiler 采集
→ 阈值断言: 启动 < 2s, 帧率 > 55fps
压力测试:
→ 大量数据 / 高频操作 / 长时间运行
→ 发现内存泄漏 / 卡顿 / 崩溃
Monkey 测试:
→ 随机事件流 (点击/滑动/按键/旋转)
→ 验证系统级稳定性 (不崩溃)
→ 命令: hdc shell aa test -m monkey -p com.example.app
三、源码/API 深度解析
3.1 单元测试示例
// entry/src/test/CacheService.test.ets
import { describe, it, expect } from '@ohos/hypium';
import { CacheService } from '../main/ets/services/CacheService';
describe('CacheServiceTest', () => {
it('setAndGet_shouldReturnSameValue', () => {
const cache = new CacheService<string>(10);
cache.set('key1', 'value1');
expect(cache.get('key1')).assertEqual('value1');
});
it('setOverCapacity_shouldEvictOldest', () => {
const cache = new CacheService<number>(2);
cache.set('a', 1);
cache.set('b', 2);
cache.set('c', 3); // 触发淘汰
expect(cache.get('a')).assertUndefined(); // 最旧被淘汰
expect(cache.get('c')).assertEqual(3);
});
it('clear_shouldEmptyCache', () => {
const cache = new CacheService<string>(5);
cache.set('x', 'y');
cache.clear();
expect(cache.size()).assertEqual(0);
});
});
3.2 UI 自动化测试示例
// entry/src/ohosTest/LoginFlowTest.ets
import { Driver, ON } from '@ohos.UiTest';
export default function loginFlowTest() {
describe('LoginFlow', () => {
it('login_success_showsHome', async () => {
const driver = Driver.create();
await driver.delayMs(1000);
// 找到输入框并输入
const userInput = await driver.findComponent(ON.id('input_username'));
await userInput.inputText('test_user');
const pwdInput = await driver.findComponent(ON.id('input_password'));
await pwdInput.inputText('123456');
// 点击登录
const loginBtn = await driver.findComponent(ON.id('btn_login'));
await loginBtn.click();
// 断言进入首页
await driver.delayMs(2000);
const home = await driver.findComponent(ON.id('home_title'));
expect(home.isVisible()).assertTrue();
});
});
}
3.3 测试门禁接入 CI
CI 流水线测试阶段:
1. 静态检查: cjlint (代码规范)
2. 单元测试: hvigor test (本地快速)
3. UI 测试: 连接设备/云真机执行
4. 覆盖率: 增量覆盖率门禁
5. 报告归档: junit.xml + 覆盖率 HTML
门禁策略:
→ 单测不过 → 阻断合入
→ 覆盖率低于门限 → 阻断合入
→ UI 测试失败 → 阻断合入
→ 性能指标劣化 → 告警 (可放宽)
四、企业级实战落地
4.1 测试分层策略
| 层级 | 覆盖对象 | 执行频率 | 失败影响 |
|---|---|---|---|
| 单元 | 核心逻辑/工具/服务 | 每次提交 | 阻断 |
| 集成 | 模块间协作 | 每日 | 阻断 |
| UI | 核心用户流程 | 每日/发版 | 阻断 |
| 性能 | 启动/帧率/内存 | 发版前 | 告警 |
| Monkey | 稳定性 | 发版前 | 阻断 |
4.2 完整示例:测试体系演示
@Entry
@ComponentV2
struct AutoTestDemo {
@Local layer: string = '待开始';
@Local passCount: number = 0;
@Local failCount: number = 0;
@Local logs: string[] = [];
private runTestFlow(): void {
this.logs = [];
this.layer = '单元测试';
this.passCount = 0;
this.failCount = 0;
this.log('🧪 ① 单元测试: CacheService');
this.log(' setAndGet: PASS');
this.log(' evictOldest: PASS');
this.log(' clear: PASS');
this.passCount += 3;
this.layer = 'XTS';
this.log('📋 ② XTS 兼容性: 系统接口契约');
this.log(' ACTS 核心子集: 92/92 PASS');
this.passCount += 92;
this.layer = 'UI 自动化';
this.log('🖱️ ③ UI 自动化: 登录→首页→下单');
this.log(' login_success: PASS');
this.log(' place_order: PASS');
this.passCount += 2;
this.layer = '性能/压力';
this.log('⚡ ④ 性能: 启动 1.8s (阈值 2s) PASS');
this.log(' 帧率 58fps (阈值 55) PASS');
this.log(' 内存 3 小时稳定, 无泄漏 PASS');
this.passCount += 3;
this.layer = 'Monkey';
this.log('🐒 ⑤ Monkey: 10000 随机事件');
this.log(' 0 崩溃 · 0 ANR · 0 卡死 PASS');
this.passCount += 1;
this.log('🏁 汇总: ' + this.passCount + ' PASS / ' + this.failCount + ' FAIL');
this.log('→ 门禁放行, 可以发版 ✅');
}
build() {
Column({ space: 12 }) {
Text('🧪 自动化测试体系演示').fontSize(20).fontWeight(FontWeight.Bold)
Text('层级: ' + this.layer).fontSize(13).fontColor('#2DA44E')
Row({ space: 8 }) {
Button('▶ 模拟测试执行').layoutWeight(1).height(40).fontSize(12)
.onClick(() => this.runTestFlow())
Button('清空').height(40).fontSize(12)
.onClick(() => this.logs = [])
}
.width('100%')
Scroll() {
Column() {
ForEach(this.logs, (l: string) => {
Text(l).fontSize(11).lineHeight(18).fontColor('#24292F').width('100%')
}, (l: string, i: number) => l + i)
}.width('100%')
}
.layoutWeight(1).width('100%').scrollBar(BarState.Off)
}
.width('100%').height('100%').padding(16)
.backgroundColor('#F6F8FA')
}
}
4.3 测试体系搭建清单
1. 先搭单元测试: 核心逻辑全覆盖,成本最低收益最高
2. 接口契约测试: XTS/自研契约测试防 API 回归
3. UI 冒烟: 核心流程自动化,发版前必跑
4. 性能基线: 关键指标入库,版本间对比
5. 稳定性压测: Monkey + 长时间运行进发版门禁
6. CI 集成: 所有测试自动执行,报告可视化
五、问题排查与性能优化
| 问题 | 原因 | 解决 |
|---|---|---|
| 用例不稳定 | 依赖外部环境 | 测试数据隔离 + Mock |
| 单测跑得慢 | 用例过多/初始化重 | 分组并行 + 轻量初始化 |
| UI 测试脆弱 | 控件定位不稳定 | 加稳定 id + 等待策略 |
| 覆盖率虚高 | 只测不校验 | 断言质量评审 |
| CI 时间太长 | 全量执行 | 分层触发 (提交/每日/发版) |
| Monkey 找不出问题 | 场景覆盖单一 | 配置事件分布 + 业务场景脚本 |
5.1 测试效率优化
1. 分层触发: 提交跑单测, 每日跑 UI, 发版跑全量
2. 并行执行: 多设备/多任务并行,缩短耗时
3. 用例分级: P0 阻断 / P1 告警 / P2 观察
4. 失败自愈: 基础设施故障自动重试,区分环境问题
5. 报告聚合: 统一看板,趋势可视,异常预警
六、高阶总结与最佳实践
- 金字塔原则:单测打底、UI 居中、E2E 少量,底层越厚越稳。
- 契约先行:XTS/接口契约测试守住系统级兼容底线。
- 门禁即纪律:测试不进 CI 等于没有测试,阻断策略要硬。
- 稳定压倒一切:脆弱的用例比没有用例更糟,先稳再扩。
- 指标可对比:性能基线化,版本间劣化自动发现。
一句话记住:自动化测试体系 = 单元测试打底 + XTS 守契约 + UI 自动化守流程 + 性能压测守指标 + Monkey 守稳定,五层防线筑起发版的质量门禁。
更多推荐


所有评论(0)