在这里插入图片描述
在这里插入图片描述

一、前置思考

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. 报告聚合: 统一看板,趋势可视,异常预警

六、高阶总结与最佳实践

  1. 金字塔原则:单测打底、UI 居中、E2E 少量,底层越厚越稳。
  2. 契约先行:XTS/接口契约测试守住系统级兼容底线。
  3. 门禁即纪律:测试不进 CI 等于没有测试,阻断策略要硬。
  4. 稳定压倒一切:脆弱的用例比没有用例更糟,先稳再扩。
  5. 指标可对比:性能基线化,版本间劣化自动发现。

一句话记住:自动化测试体系 = 单元测试打底 + XTS 守契约 + UI 自动化守流程 + 性能压测守指标 + Monkey 守稳定,五层防线筑起发版的质量门禁。

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐