👋 你好,欢迎来到我的博客!我是【菜鸟学鸿蒙】
   我是一名在路上的移动端开发者,正从传统“小码农”转向鸿蒙原生开发的进阶之旅。为了把学习过的知识沉淀下来,也为了和更多同路人互相启发,我决定把探索 HarmonyOS 的过程都记录在这里。
  
  🛠️ 主要方向:ArkTS 语言基础、HarmonyOS 原生应用(Stage 模型、UIAbility/ServiceAbility)、分布式能力与软总线、元服务/卡片、应用签名与上架、性能与内存优化、项目实战,以及 Android → 鸿蒙的迁移踩坑与复盘。
  🧭 内容节奏:从基础到实战——小示例拆解框架认知、专项优化手记、实战项目拆包、面试题思考与复盘,让每篇都有可落地的代码与方法论。
  💡 我相信:写作是把知识内化的过程,分享是让生态更繁荣的方式。
  
   如果你也想拥抱鸿蒙、热爱成长,欢迎关注我,一起交流进步!🚀

前言

我跟你说句大实话:鸿蒙项目最容易出现一种“迷之自信”——功能在我手机上跑得好好的呀!然后一上架:平板分栏抖一下、2in1 窗口一拖就崩、跨设备协同偶现失败……你盯着告警日志,心里只有四个字:**“我真该测…”**🥲
  所以这章我不跟你扯虚的,直接把“鸿蒙测试体系建设”拆成四块:单元测试、UI 自动化、分布式测试难点、CI 集成方案。你照着搭,至少能把“靠祈祷上线”的概率按在地上摩擦。

1. 单元测试:先把“可测的业务逻辑”从 UI 里救出来🛟

鸿蒙的测试体系里,单元测试通常做两件事:

  • 纯逻辑:计算、规则、策略、序列化、校验、状态机
  • 可替身的依赖:网络、存储、时间、设备能力(用 mock/桩替代)

在 HarmonyOS 的测试能力里,@ohos.application.testRunner 用于准备单元测试环境与运行用例,你可以理解为“测试执行入口与生命周期”那套东西。

1.1 一个“别太花哨但真能用”的 ArkTS 单元测试例子

思路:把业务逻辑写成可注入依赖的 class,测试里直接 new,然后断言输出。

// src/main/ets/domain/PriceCalculator.ts
export class PriceCalculator {
  // 满减:满 200 - 20;再叠加会员 95 折
  calc(origin: number, isVip: boolean): number {
    let v = origin
    if (v >= 200) v -= 20
    if (isVip) v *= 0.95
    // 统一保留两位
    return Math.round(v * 100) / 100
  }
}
// src/ohosTest/ets/test/PriceCalculator.test.ets (示意结构)
import { PriceCalculator } from '../../main/ets/domain/PriceCalculator'

function assertEq(actual: number, expected: number, msg?: string) {
  if (actual !== expected) {
    throw new Error(msg ?? `assert failed: actual=${actual}, expected=${expected}`)
  }
}

export default function run() {
  const c = new PriceCalculator()

  assertEq(c.calc(199, false), 199, '未满减不应变化')
  assertEq(c.calc(200, false), 180, '满减应为 180')
  assertEq(c.calc(200, true), 171, '满减 + 95 折应为 171')
}

我个人的“嘴硬但有效”建议:

  • 单测别测 UI,只测能稳定复现的逻辑
  • 把网络、存储、时间封成接口(比如 Clock.now()),测试里用 fake 实现,别让用例“靠天吃饭”。

2. UI 自动化测试:别让回归靠“人肉点点点”😮‍💨

鸿蒙 UI 自动化这块,官方提供了 @ohos.UiTest:支持点击、长按、滑动、控件查找、按键注入、截图等能力,并提供 Driver / Component / On 等核心对象。
注意它还有个很重要的限制:接口不支持并发调用(别想着同时起多线程狂点屏幕,容易把自己点到怀疑人生)。

2.1 一段能落地的 UiTest 脚本(登录页举例)

// src/ohosTest/ets/test/Login.ui.test.ets
import UiTest from '@ohos.UiTest'

export default async function run() {
  const driver = await UiTest.Driver.create()

  // 通过 id 找控件(On.id 是官方推荐的控件特征方式):contentReference[oaicite:3]{index=3}
  const userInput = await driver.findComponent(UiTest.On.id('user_input'))
  const pwdInput  = await driver.findComponent(UiTest.On.id('pwd_input'))
  const loginBtn  = await driver.findComponent(UiTest.On.id('btn_login'))

  await userInput.inputText('daniel')
  await pwdInput.inputText('123456')
  await loginBtn.click()

  // 等页面稳定(避免动画/异步请求导致断言抖动)
  await driver.waitForIdle()

  // 断言 toast / 弹窗等(UiTest 支持事件观察能力):contentReference[oaicite:4]{index=4}
  // 示例:这里按你的项目实际 UI 表现调整
  // await driver.createUIEventObserver().once('toastShow', ...)
}

UI 自动化的“防翻车三件套”:

  1. 控件可定位:id/description/type 这类特征要规范(别今天叫 btn1 明天叫 login_ok 😭)
  2. 等待策略waitForIdle / waitForComponent 比硬 delayMs(2000) 可靠得多
  3. 断言要稳:断言“页面关键状态”,别断言像素级位置(窗口模式一变你就哭)

3. 分布式测试难点:最难的不是“写用例”,是“让它稳定”😤

分布式(多设备协同)测试的难点,本质是:你的系统变量太多了。常见“阴间问题”包括:

3.1 设备侧的不确定性

  • 设备发现/认证偶发慢
  • 网络切换(Wi-Fi/热点/蓝牙)导致链路抖动
  • 两端系统负载不同(A 很闲,B 在后台疯狂杀进程)

3.2 时间与顺序问题(最恶心)

  • A 触发协同,B 还没 ready
  • 事件到达顺序不同,导致 UI 状态机走岔路
    **结论:**分布式测试一定要有“可观测性”:关键节点打点、统一 traceId、同步完成回调可追踪。

3.3 用例编排与结果采集

OpenHarmony 体系里,xDevice 是测试调度框架核心组件,负责用例分发执行与结果采集,并能生成报告;其仓库也把 command/config/driver/report 等模块职责写得很清楚。
这类调度框架的价值在分布式测试里非常明显:你得让“多设备、多用例、多轮次”跑得可控、结果可收敛,否则你永远在复现“偶现”😵‍💫。

4. CI 集成方案:把测试从“人手跑一次”变成“每次提交都跑”✅

这里我给你两条路线,你按项目形态选:

路线 A:HarmonyOS 应用(DevEco/Hvigor)——“构建产物 + 跑测试 + 出报告”

Hvigor 是 HarmonyOS 应用构建的任务调度工具,负责编译构建产物包,并支持并行/增量等能力(对 CI 提速很关键)。([developer.huawei.com][4])

一个实用的 CI 分层(我强推):

  1. Lint/静态检查:快,先拦住低级错误
  2. 单元测试:快,必须跑
  3. UI 自动化(冒烟):只跑核心 10~20 条(登录、首屏、主链路)
  4. UI 自动化(全量回归):夜间跑(别每次提交都把设备跑冒烟)

UiTest 不支持并发调用 ,所以“同一台设备上并发跑多条 UI 用例”这条路一般走不通;正确姿势是:多台设备并行、单设备串行

Jenkinsfile(示意)(你可以改成 GitLab CI/YAML,意思一样):

pipeline {
  agent any
  stages {
    stage('Build') {
      steps {
        sh './hvigorw clean'
        sh './hvigorw assembleHap' // 具体任务名按你的工程配置
      }
    }
    stage('UnitTest') {
      steps {
        sh './hvigorw test' // 按项目测试任务配置调整
      }
    }
    stage('UI Smoke') {
      steps {
        // 连接设备/模拟器后执行 Instrument/UI 测试(示意)
        sh './hvigorw instrumentTest --testsuite smoke'
      }
    }
    stage('Report') {
      steps {
        archiveArtifacts artifacts: '**/test-results/**', fingerprint: true
      }
    }
  }
}

路线 B:OpenHarmony / 系统侧(xDevice)——“调度执行 + 采集报告 + 统一归档”

如果你做的是 OpenHarmony 设备/系统栈相关测试,xDevice 的定位就是“调度执行的底座”,包含用例执行、结果收集与报告模块。
CI 里你要做的是:

  • 准备设备连接(USB/串口/网络)
  • 下发用例包/配置
  • 调用 xDevice 执行
  • 收集 report 输出(XML/HTML/自定义报告),上传到制品库

结尾:测试体系这东西,早建早享受;晚建……晚点崩溃😄

你会发现:鸿蒙测试体系建设的本质,不是“我写了多少用例”,而是——

  • 单测让逻辑可控
  • UI 自动化让回归可重复(UiTest 这套就是干这个的 )
  • 分布式测试让协同可验证(靠调度框架把多设备跑起来
  • CI 让质量变成流程,而不是口号(Hvigor 构建能力在这里很关键

📝 写在最后

如果你觉得这篇文章对你有帮助,或者有任何想法、建议,欢迎在评论区留言交流!你的每一个点赞 👍、收藏 ⭐、关注 ❤️,都是我持续更新的最大动力!

我是一个在代码世界里不断摸索的小码农,愿我们都能在成长的路上越走越远,越学越强!

感谢你的阅读,我们下篇文章再见~👋

✍️ 作者:某个被流“治愈”过的 移动端 老兵
📅 日期:2025-11-05
🧵 本文原创,转载请注明出处。

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐