
鸿蒙预览场景模拟ohos/hamock 模拟框架详解与源码级实践指南【免费下载链接】cann-recipes-harmony-infer本项目为鸿蒙开发者提供基于CANN平台的业务实践案例方便开发者参考实现端云能力迁移及端侧推理部署。项目地址: https://gitcode.com/cann/cann-recipes-harmony-inferHamock 是 OpenHarmony 生态中的轻量模拟框架专为 DevEco Studio 预览场景设计允许开发者在组件预览时通过MockSetup装饰器重定义组件方法或重赋值组件属性从而让 UI 预览摆脱对真实业务数据与接口的依赖。本文以当前仓库cann-recipes-harmony-infer中 Soble 案例所依赖的 ohos/hamock 源码包 为蓝本结合框架底层实现系统讲解 Hamock 的安装、API 使用、执行原理与约束限制帮助你在鸿蒙应用开发中快速搭建可独立运行的预览 Mock 环境。一、Hamock 是什么预览场景的模拟框架Hamock 是 OpenHarmony 上针对预览场景DevEco Studio Previewer提供的模拟框架。它的核心能力是让开发者在不修改业务代码的前提下为 UI 组件指定一组“预览专用的替身数据”——在预览器打开组件时用 Mock 数据替换掉原本依赖网络请求、原生能力或复杂状态初始化的方法与属性使页面预览始终可运行、可展示。它解决的问题非常具体ArkTS 声明式范式组件在预览时aboutToAppear、构造参数、Prop等属性的初始化链路往往依赖外部环境如模型加载、接口回调一旦依赖缺失预览器便无法渲染出完整页面。Hamock 通过MockSetup装饰器提供了一条“预览专用初始化通道”在不触碰业务逻辑的前提下注入 Mock 行为。从当前仓库的依赖配置可以确认 Hamock 的实际接入方式在 Soble 工程的 oh-package.json5 中ohos/hamock以1.0.0版本被声明在devDependencies中与ohos/hypium并列在 oh-package-lock.json5 中锁定了版本与校验信息说明它作为开发期依赖随工程一并分发。二、下载安装Hamock 通过 ohpmOpenHarmony 包管理器安装命令如下ohpm install ohos/hamock安装完成后工程中会生成对应的锁文件与依赖目录。在本仓库中安装产物即位于 harmony_infer/harmony_os_next/Soble/oh_modules/ohos/hamock/ 目录下其 oh-package.json5 声明了该包的元信息name:ohos/hamockversion:1.0.0description:A mock framework for OpenHarmony application.main:index.ets入口模块对外导出MockSetup、MockKit、when、ArgumentMatcherstypes:index.d.tsTypeScript 类型声明供 IDE 智能提示与静态检查使用license:Apache-2.0从 index.ets 可以看到包的导出面export { MockSetup, MockKit, when } from ./src/main/mock/MockKit; export { ArgumentMatchers } from ./src/main/mock/ArgumentMatchers;也就是说安装后你在业务代码中实际可用的是四个核心导出MockSetup装饰器、MockKit模拟器、when存根配置入口与ArgumentMatchers参数匹配器。三、核心概念MockSetup 装饰器MockSetup用于修饰 Mock 方法仅支持声明式范式的组件。当开发者预览该组件时预览运行时将在组件初始化时执行被MockSetup修饰的方法。开发者可以在这个被修饰的方法内重定义组件的方法或重赋值组件的属性这些变更只在预览时生效不影响真机运行。说明MockSetup修饰的方法仅在预览场景会自动触发并先于组件的aboutToAppear执行。在仓库附带的 MockKit.ts 源码 中可以看到MockSetup的底层实现它本质上是对组件aboutToAppear生命周期的“前置包装”function MockSetup(target: Object, propertyName: string | Symbol, descriptor: TypedPropertyDescriptor() void): void { const aboutToAppearOrigin target.aboutToAppear; const setup descriptor.value; target.aboutToAppear function (...args: any[]) { if (target.__Param) { // copy attributes and params of the original context // 将组件上下文中的属性与参数复制到当前执行上下文 } if (setup) { // apply the mock content setup.apply(this); // 先执行 MockSetup 修饰的方法 } if (aboutToAppearOrigin) { // append to aboutToAppear function of the original context aboutToAppearOrigin.apply(this, args); // 再执行原始 aboutToAppear } } }这段实现揭示了三个关键设计执行顺序MockSetup方法先于组件原有aboutToAppear执行因此 Mock 注入的数据可以在业务初始化逻辑读取之前就位上下文一致性通过target.__Param将组件上下文含Prop等参数复制到装饰器方法执行上下文保证 Mock 方法内访问this.xxx语义正确零侵入原始aboutToAppear被保存并追加执行业务生命周期逻辑不被破坏。四、使用示例一Mock UI 组件的方法在 ArkTS 页面代码中引入 Hamock在目标组件中定义一个方法并用MockSetup修饰在该方法内使用MockKit模拟目标方法import { MockKit, when, MockSetup } from ohos/hamock; Entry Component struct Index { ... MockSetup randomName() { let mocker: MockKit new MockKit(); let mockfunc: Object mocker.mockFunc(this, this.method1); // mock 指定的方法在指定入参的返回值 when(mockfunc)(test).afterReturn(1); } ... // 业务场景调用方法 const result: number this.method1(test); // in previewer, result 1 }上例中this.method1(test)在真机上执行真实逻辑而在预览器中会命中 Mock 存根并返回1。从 MockKit.ts 的源码看mockFunc的替换机制是通过findName找到目标方法在对象上的属性名然后用包装函数f覆盖originalObject[name]同时把原方法保存在recordMockedMethod映射中以便恢复。包装函数在执行时调用getReturnInfo查询存根表stubs有匹配的存根action执行存根动作并返回结果无匹配存根返回undefined。每次被调用时recordMethodCall都会以“方法名(参数列表)”为键记录调用次数为后续的verify断言提供数据。when的语义在 ExtendInterface.ts 中实现when(mockfunc)(test)本质是先通过stub()暂存参数这里是入参test随后.afterReturn(1)调用stubMockedCall把“入参 → 返回动作”的映射写入 MockKit 的stubs表。框架提供的全部存根行为包括方法行为典型用途afterReturn(value)固定返回指定值替代返回固定数据的接口/方法afterReturnNothing()返回undefined模拟无返回值的调用afterAction(action)执行自定义动作函数模拟带副作用的调用afterThrow(msg)抛出指定异常信息模拟异常分支五、使用示例二Mock UI 组件的属性在 ArkTS 页面代码中引入 Hamock在目标组件中定义一个方法并用MockSetup修饰在该方法内对需要 Mock 的属性重新赋值import { MockSetup } from ohos/hamock; Component struct Person { Prop species: string; ... // 在 MockSetup 片段中定义对象属性 MockSetup randomName() { this.species primates; } ... // 业务场景调用属性如果从初始化到调用期间该属性无变化 const result: string this.species; // in previewer, result primates }上例中Prop species在预览时会被赋值为primates从而让依赖该属性的 UI 分支能够正常渲染。属性的 Mock 不经过MockKit存根表而是依赖MockSetup方法先于aboutToAppear执行的时序赋值动作发生在业务代码读取属性之前。六、深入原理MockKit 的完整 API 与验证机制除了MockSetup与when/afterReturn组合MockKit 还提供了一组面向对象级 Mock 与调用验证的 API类型声明见 index.d.ts6.1 MockKit 核心方法方法说明mockFunc(obj, func)将对象上的指定方法替换为 Mock 函数返回包装函数mockObject(obj)浅拷贝对象并将其上所有函数类型成员逐一 Mock返回 Mock 后的对象副本verify(methodName, argsArray)校验某方法以指定参数被调用的次数返回VerificationModeignoreMock(obj, func)还原指定对象的指定方法忽略 Mockclear(obj)还原指定对象上所有被 Mock 过的方法clearAll()清空当前 MockKit 实例的全部存根与调用记录其中verify配合 VerificationMode.js 提供次数断言export interface VerificationMode { times(count: Number): void // 断言恰好调用 count 次 never(): void // 断言从未调用 once(): void // 断言恰好调用 1 次 atLeast(count: Number): void // 断言至少调用 count 次 atMost(count: Number): void // 断言至多调用 count 次 }6.2 ArgumentMatchers 参数匹配when(mockfunc)的入参除了字面量还可以使用参数匹配器实现“任意值/按类型/按正则”的存根匹配。匹配器定义在 ArgumentMatchers.ts 中export class ArgumentMatchers { static any; // 匹配任意入参 static anyString; // 匹配任意字符串 static anyBoolean; // 匹配任意布尔值 static anyNumber; // 匹配任意数字 static anyObj; // 匹配任意对象 static anyFunction; // 匹配任意函数 static matchRegexs(Regex: RegExp): void // 按正则匹配字符串入参 }典型用法// 只要入参是任意字符串就返回 1 when(mockfunc)(ArgumentMatchers.anyString).afterReturn(1); // 入参匹配正则 /^test/ 时返回 2 when(mockfunc)(ArgumentMatchers.matchRegexs(/^test/)).afterReturn(2);从源码实现看stubApply在写入存根时会把匹配器映射为内部占位键如any String而getReturnInfo在查询时通过matcheReturnKey做类型推导与正则匹配从而把“匹配器定义”与“按入参查存根”两阶段衔接起来。6.3 一次完整 Mock 的调用链综合源码一次方法 Mock 的完整链路为new MockKit()初始化存根表stubs、调用记录表recordCalls、被 Mock 方法记录表recordMockedMethodmocker.mockFunc(this, this.method1)定位属性名并替换为包装函数原方法被存档when(mockfunc)(test)暂存参数.afterReturn(1)将「入参 → 返回 1 的动作」写入stubs预览器触发组件初始化MockSetup方法执行先于aboutToAppear完成上述注册业务代码调用this.method1(test)命中包装函数getReturnInfo查表得到返回 1 的动作并执行同时记录一次调用如需断言用verify(method1, [test]).once()校验调用次数。七、约束与限制根据 Hamock 官方 README即本仓库中的 hamock README该框架在以下版本验证通过组件版本DevEco Studio4.1 (4.1.3.400)SDKAPI11 (4.1.0.36)MockSetup仅在 API11 支持。因此若目标工程的 SDK 版本低于 API11无法使用MockSetup装饰器只能考虑在预览之外的其他测试手段从 CHANGELOG.md 的版本记录看1.0.0-rc首次提供 DevEco Studio 预览器场景使能的MockSetup装饰器1.0.0修复了once断言问题本仓库锁定的是修复后的1.0.0正式版使用MockSetup时Mock 逻辑仅作用于预览场景真机运行不受影响这既是能力也是边界——不能把预览 Mock 当作单元测试替身或运行时数据源。八、在仓库中的工程化落地本仓库的 Soble 案例工程 是 Hamock 的典型落地场景该工程以ohos/hamock: 1.0.0作为devDependencies依赖与ohos/hypium一并用于开发调试详见 oh-package.json5 与 oh-package-lock.json5。在涉及 Sobel 图像处理、模型推理等依赖原生能力与算力环境的页面中预览器无法真正执行端侧推理此时便适合用 Hamock 在预览场景中注入可展示的模拟数据保证 UI 开发与调试的独立进行。需要提醒的是仓库对oh_modules目录是随依赖安装自动生成的若在你的工程中复现请以ohpm install拉取对应版本而不要手工拷贝本仓库的oh_modules内容。九、参与贡献与开源协议Hamock 遵循 Apache License 2.0 开源协议详见其包声明中的license字段。若在使用过程中发现缺陷可以向 OpenHarmony 的 testfwk 相关仓库提交 Issue 或 PR 参与共建。结语Hamock 以“预览场景专用”为定位通过MockSetup装饰器 MockKit存根机制为 ArkTS 声明式组件的 UI 预览提供了一条低成本、零侵入的 Mock 通道。结合其源码实现我们可以清晰地看到方法 Mock 基于“替换属性 存根表查询 调用记录”三件套属性 Mock 依赖“先于aboutToAppear执行”的生命周期时序而when/ArgumentMatchers/VerificationMode则分别承担存根配置、灵活匹配与调用验证的职责。掌握这套机制你就能在鸿蒙应用开发中让预览器“跑得起来、看得见数据”显著提升 UI 侧开发调试效率。【免费下载链接】cann-recipes-harmony-infer本项目为鸿蒙开发者提供基于CANN平台的业务实践案例方便开发者参考实现端云能力迁移及端侧推理部署。项目地址: https://gitcode.com/cann/cann-recipes-harmony-infer创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考