前言
在移动端开发中,单元测试是构建健壮移动应用的基石,然后在工程实践中,单元测试往往是资源最密集,最具挑战的环节之一。在做单元测试工作时遇到的难题往往如下:
- 难以捉摸的覆盖率:手动编写测试总会留下盲点,尤其是在复杂的 UI 逻辑、设备碎片化带来的边界条件和错误处理上;
- 参差不齐的质量:在缺乏严格统一范式的情况下,测试套件会沦为风格迥异的代码“补丁集”,可读性差,维护成本极高;
- 重复的样板代码:相当一部分测试工作是在编写重复的初始化、清理和模拟(Mock)逻辑,这极大地消耗了开发者的心力与时间。
为了解决这些问题,本文引入了 Qoder Rules 来辅助生成高质量的移动端单元测试。Qoder Rules 是 Qoder IDE 提供的一种代码上下文规则系统,可以为 AI 助手提供项目特定的知识和约束,从而生成更符合项目规范的代码。
本文旨在呈现一套完整的、从零到一创建和优化移动端单元测试 Qoder Rules 的实践方案,并且本文以开发移动端性能体验监控 SDK 为实战案例,详细展示 iOS、Android 以及 HarmonyOS NEXT 三端如何通过 Qoder Rule 辅助生成健壮的单元测试,从而提高工程质量。
Qoder Rules 使用方式说明
官方文档链接:https://docs.qoder.com/user-guide/rules
Qoder rule 工作模式
- 创建规则:在 Qoder IDE 右上角,点击用户图标,选择 Qoder 设置,在左侧导航窗格中点击 规则。点击添加,然后在顶部搜索栏中输入唯一的规则名并按确认。
- 存储位置:规则存放在 ./qoder/rules 目录中,仅对当前项目生效。可以通过 Git 进行版本管理,团队共享。也可以通过配置 .gitignore 来实现仅本地使用。
- 工作模式:Qoder Rules 可以为大语言模型补充项目特定的上下文和规则,从而提高回答质量。

Qoder rules 生效规则
Qoder Rules 支持四种不同的生效规则,每种规则适用于不同的场景:
- 始终生效
- 使用场景:项目核心架构和设计原则 / 全局编码规范和命名约定 / 项目结构和模块依赖关系 / 通用的最佳实践
- 示例:比如README.md、module-architecture.md、naming-conventions.md 等规则文件使用此模式,确保 AI 助手始终了解项目的基本结构和规范。
- 指定文件生效
- 使用场景:特定文件类型的编码规范 / 语言特定的最佳实践 / 文件类型相关的工具使用
- 示例:coding-style.md 规则针对源代码文件(*.h, *.m, *.mm, *.swift)自动生效,确保代码风格一致性。
- 模型决策
- 使用场景:特定功能的详细指导 / 复杂流程的步骤说明 / 专业领域的知识规范
- 示例:单元测试unit-testing.md 规则可以使用此模式,当涉及单元测试相关任务时,AI 助手会主动获取这些规则。
- 手动引入
- 使用场景:临时性的特殊需求 / 调试和故障排除指南 / 高级配置和优化建议
- 示例:build-and-debug.md 和 contribution-guide.md 需要手动引用,用于解决特定问题或进行代码贡献。
官方最佳实践与约束
- 保持简洁,所有的活跃规则文件合计最多允许 100000 个字符,超出部分会被截断
- 提供有效的良好代码示例以指导模型;
- 需要根据模型输出不断完善规则;
如何生成 Qoder Rules
在新建完成 Qoder Rules 之后,在 .qoder/rules 文件夹下可以看到一个空的规则文件。接下来可以结合 Prompt 生成你所需要的规则文件,再进行微调。以项目架构上下文规则为例,在新建一个规则 project-structure.md 后,在聊天框内可以输入如下示例。

移动端单测优化的实战与微调
在了解了 Qoder Rules 的工作模式后,接下来实战验证效果。本文以用户体验监控 (RUM)SDK 项目工程为例,用户体验监控 SDK 移动端覆盖了 iOS、Android 和 HarmonyOS 平台,实现了用户行为数据的无感知采集。代码质量直接决定 SDK 的稳定性,我们将通过设计高效的 Prompt 来生成高质量的 Qoder Rules,从而提升单测行覆盖率。
前置准备:构建架构索引以及上下文 Rules
首先需要让 AI 理解工程结构。除了通过Qoder的代码索引外,建议显式定义基础规范文件(如 android-project-structure.md),告知 AI 哪些是核心模块,哪些是第三方库。以 Android 平台为例,基础规则具体可以包含以下内容。
| 文件 | 触发方式 | 主要内容 |
| android-project-structure.md | always | 项目架构、模块说明、构建配置 |
| development-workflow.md | manual | 开发环境、分支策略、提交规范 |
| gradle-build-standards.md | glob(.gradle) | Gradle 配置、依赖管理、构建任务 |
| sdk-api-design-patterns.md | glob(.java) | 设计模式、API 设计、线程安全 |
| proguard-configuration.md | glob(proguard.pro) | 混淆规则、SDK 保护、第三方库配置 |
其中 HarmonyOS 平台,需要额外补充对 ArkTS 语言的规则。
| 文件 | 触发方式 | 主要内容 |
| arkts.md | always | ArkTS 语言特性,与 TypeScript 语言的区别 |
如何设计高效的 Prompt
Android 端 Prompt 设计:攻克环境依赖
Android 单元测试的核心痛点在于对 Android Framework 的依赖。如果直接测试,往往会因为缺少系统环境而报错。因此,Android 端的 Prompt 设计核心在于隔离与模拟。
- Prompt 核心策略
本文构建了一个结构化的 Prompt,旨在生成一份强制性的单元测试规则。以下是优化后的 Android Rule 生成指令:
请为 Android SDK 创建一份单元测试规则 (@android-unit-test-guide.md),需严格遵守以下约束:
- 技术栈锁定:强制使用 JUnit4 + Mockito + Robolectric。
- 核心原则:
- 业务隔离:测试聚焦业务逻辑,严禁测试 Android 系统 API(如 Context.getSystemService)或第三方库内部实现。
- 环境模拟:严禁使用反射修改 Build.VERSION 等系统静态字段,必须使用参数化测试或 Robolectric 提供的 Shadow 对象。
- 代码模板规范:
- 类结构:必须包含 @Before (初始化 Mock) 和 @After (清理静态 Mock,防止污染)。
- 命名:测试方法遵循 test{Method}{Scenario}{Expected} 格式。
- 工作流闭环:
- 生成代码后,必须自动执行 ./gradlew :module:testDebugUnitTest。
- 语言约束:注释与断言描述强制使用英文,便于开源维护。
- 设计解读
这个 Prompt 解决了一个核心矛盾:AI 倾向于写这就调用系统 API 的代码,导致本地单测跑不通。通过“严禁反射系统字段”和“强制 Robolectric”的约束,我们确保了生成的测试用例是可以在本地 JVM 上稳定运行的。
iOS 端 Prompt 设计:攻克工程结构
与 Android 不同,iOS (Xcode) 的痛点在于文件系统与工程引用的分离。仅仅创建一个 .swift 文件并不能让它被 Xcode 识别。因此,iOS 的 Prompt 设计核心在于自动化工作流。
- Prompt 核心策略
iOS 的规则设计需要包含“动作链”,即生成文件后必须触发脚本操作。以下是 iOS Rule 的生成指令:
请为 iOS SDK 创建一份单元测试规则 (@iOS-unit-test-guide.md),需包含以下自动化逻辑:
- 智能场景识别:
- 新建场景:先检查单测文件是否存在。若不存在,使用 XCTest 标准模板生成,并立即执行 Scripts/add_file_to_target.sh 脚本将其挂载到 Xcode Target;
- 优化场景:若文件已存在,读取代码并补充边界条件断言。
- 验证闭环:
- 修改完成后,必须执行 cd Scripts && ./run-unittest.sh 进行验证。
- 若验证失败,AI 需自动读取错误日志并尝试修复。
- 测试架构规范:
- 核心覆盖:必须包含单例模式(Singleton)、主要功能(Main Logic)、边界条件(Nil/Empty)和错误处理(Error Handling)四大场景。
- 语言约束:注释必须使用英文,采用 AAA (Arrange-Act-Assert) 风格。
- 设计解读
iOS 的 Prompt 引入了 add_file_to_target.sh 这一关键脚本。这是为了解决 AI 无法直接修改 .xcodeproj 文件(结构过于复杂)的问题。通过“生成文件 -> 脚本挂载 -> 脚本运行”的自动化链路,确保了 AI 生成的代码不仅逻辑正确,还能真正集成到工程中。
HarmonyOS 端 Prompt 设计:攻克语言特性
HarmonyOS 的单元测试基于 @ohos/hypium 框架,其核心痛点在于 ArkTS 语言的严格静态类型限制 以及 测试套件的注册机制。传统的 TypeScript 测试写法(如使用 any、动态对象字面量)在 ArkTS 中会直接导致编译失败。
- Prompt 核心策略
HarmonyOS 的 Prompt 设计需要扮演“语言编译器”和“框架管家”的双重角色。
请为 HarmonyOS SDK 创建一份单元测试规则 (@harmony-unit-test-guide.md),需严格遵守以下约束:
- 语言编译器(ArkTS 严格模式):
- 类型铁律:严禁使用 any 或 unknown。所有对象字面量必须先定义 interface。
- 泛型强制:Promise 必须显式指定泛型(如 Promise),禁止依赖类型推断。
- 断言修正:检测并修正不支持的断言。例如:严禁使用 assertNotEqual(Hypium 不支持),必须转换为 expect(a !== b).assertTrue()。
- 使用测试框架(@ohos/Hypium):
- 路径映射:根据 src/main/ets 的目录结构,精确计算 src/ohosTest/ets 下的测试文件路径和 import 路径(注意 ../../ 的层级);
- 自动注册:生成测试文件后,必须输出指令提示用户(或尝试自动修改)将测试入口注册到 src/ohosTest/ets/test/List.test.ets 文件中,否则测试无法运行。
- 测试架构:
- 异步规范:对于异步方法,强制使用 async/await 配合 done 回调或 Promise 链式调用,防止测试提前结束。
- 生命周期:正确使用 beforeAll 进行全局初始化,beforeEach 重置单例状态。
- 设计解读
对于 HarmonyOS 平台,主要难点在于 ArkTS 的语言特性,目前 AI 对于 ArkTS 语言的语法会更多按照 TypeScript 处理,因此需要输入两种语言的区别来辅助 AI 生成 ArkTS 语言。另外,HarmonyOS 平台的测试框架,也需要给一些清晰的示范样例。与 Android 和 iOS 的不同之处在于,在 HarmonyOS 生成单测之后,没有验证环节。相比于命令行验证,在 Qoder 生成测试代码后回到 DevEco Studio 中运行验证会相对方便。
小结
进一步地,本文提炼出一套跨平台的优化单元测试的 Prompt (Rule) 设计通用法则。无论什么技术栈,一个高质量的工程化 Prompt 应包含以下四个维度:
- 角色与边界
- 明确目标:不仅仅是“写个测试”,而是“基于 xxx 架构生成用于 xxx 场景的测试”。
- 依赖隔离:明确告知 AI “不测什么”。例如:不测系统 API、不测第三方库、不测简单的 Getter/Setter。这是减少无效代码的关键。
- 结构化约束
- 模板强制:提供“黄金模板”,规定好 Setup/Teardown 的写法、命名规范(如 test_Input_Output)。AI 模仿能力强,给模板比给指令更有效。
- 语言统一:对于有开源或国际化需求的项目,强制要求英文注释和 Commit Message,避免中英文混排。
- 工具链集成
- Android:利用构建工具(Gradle)的灵活性,通过规则约束依赖库版本(Robolectric/Mockito);
- iOS:利用脚本(Shell/Ruby)弥补 IDE 的封闭性,解决文件引用问题。
- 环境复原:强调测试后的清理工作(如 Mock 对象的关闭、单例的重置),防止测试污染。
- 验证闭环 :这是最重要的一环。Prompt 不能止步于“生成代码”,必须包含“验证代码”:
- 指令:生成后执行什么命令?(./gradlew test 或 ./run-unittest.sh)。
- 自愈:如果命令报错,AI 应被指示去读取 Log 并尝试修复(Self-Correction)。
- 策略:对于新建文件,必须先挂载;对于修改文件,必须做回归测试。
Qoder Rules 的内容
完整的 Rule 往往包含了上百行约束,为了方便大家理解,本文通过流程图的方式展示各个端的 Rule 的架构设计。
Android Qoder Rule
flowchart LR
Start[开始: Android 单测生成] --> Analyze{分析依赖类型}
Analyze -- 纯逻辑类 --> UnitPlan[普通 JUnit4]
Analyze -- 依赖 Android SDK --> RoboPlan[Robolectric]
Analyze -- 依赖静态/单例 --> MockPlan[MockedStatic]
subgraph MockStrategy [Mock 策略构建]
direction TB
DefMocks[定义 @Mock] --> DefStatic[定义 Static]
DefStatic --> Setup[生成 @Before]
Setup --> Teardown[生成 @After]
end
UnitPlan --> GenCode
RoboPlan --> GenCode
MockPlan --> MockStrategy --> GenCode
GenCode[生成/修改 Java 测试类] --> ConstraintCheck{规则合规检查}
%% 优化点:合并违规分支,使用紧凑节点,避免交叉
ConstraintCheck -- 发现违规 --> AutoFix(AI 修正: 替换反射 / 移除系统API)
AutoFix -.-> GenCode
ConstraintCheck -- 通过 --> RunGradle[执行 ./gradlew test]
RunGradle --> Result{构建成功?}
Result -- 否 --> ReadError[读取堆栈修复] -.-> GenCode
Result -- 是 --> End[完成]
style RoboPlan fill:#e3f2fd,stroke:#1565c0
style ConstraintCheck fill:#fff3e0,stroke:#ef6c00
style MockStrategy fill:#f3e5f5,stroke:#7b1fa2
style AutoFix fill:#fff,stroke:#ef6c00,stroke-dasharray: 5 5
style ReadError fill:#fff,stroke:#333,stroke-dasharray: 5 5iOS Qoder Rule
iOS 的核心在于解决 Xcode 文件索引问题。我们不需要展示所有配置,只需展示 AI 是如何通过 Rule 调用脚本的。
flowchart LR
Start[开始: 编写/优化单测] --> CheckFile{检查文件是否存在?}
CheckFile -- 不存在 --> GenScenario[场景1: 新建测试]
GenScenario --> GenCode[应用 XCTest 模板生成代码]
GenCode --> AddScript[执行 Scripts/add_file_to_target.sh]
AddScript --> TargetCheck{挂载成功?}
TargetCheck -- 否 --> FixPath[AI 分析路径并修复] --> AddScript
TargetCheck -- 是 --> RunTest
CheckFile -- 存在 --> OptScenario[场景2: 优化现有测试]
OptScenario --> ReadCode[读取并分析现有代码]
ReadCode --> Refactor[补充边界条件/修复断言]
Refactor --> RunTest
RunTest[执行 Scripts/run-unittest.sh] --> Verify{测试通过?}
Verify -- 是 --> End[完成: 提交代码]
Verify -- 否 --> AnalyzeLog[AI 读取 xcodebuild 日志]
AnalyzeLog --> FixCode[修复逻辑/Mock] --> RunTest
style Start fill:#e1f5fe,stroke:#01579b
style RunTest fill:#e8f5e9,stroke:#2e7d32
style AddScript fill:#fff3e0,stroke:#ef6c00HarmonyOS Qoder Rule
鸿蒙 ArkTS 的语法限制严格,Qoder Rule 的重点在纠正。
flowchart LR
Start[开始: HarmonyOS 单测生成] --> GenCode[生成 .test.ets 初稿]
%% 阶段一:ArkTS 语法编译器模式
GenCode --> SyntaxCheck{ArkTS 语法检查}
SyntaxCheck -- 发现违规 --> AutoFix(AI 修正: <br/>1. 消除 Any/Unknown <br/>2. 补充 Promise 泛型 <br/>3. 修正不支持的断言)
AutoFix -.-> GenCode
%% 阶段二:Hypium 框架管家模式
SyntaxCheck -- 语法通过 --> PathCalc[计算 import 相对路径]
PathCalc --> RegCheck{检查 List.test.ets}
RegCheck -- 未注册 --> DoReg[自动注册: <br/>注入 import + 调用入口函数]
DoReg --> RunTest
RegCheck -- 已注册 --> RunTest[执行 hvigor test]
RunTest --> Verify{测试通过?}
Verify -- 否 --> FixLogic[修复业务逻辑] -.-> RunTest
Verify -- 是 --> End[完成]
%% 样式定义
style AutoFix fill:#fff,stroke:#ef6c00,stroke-dasharray: 5 5
style DoReg fill:#e3f2fd,stroke:#1565c0
style SyntaxCheck fill:#fff3e0,stroke:#ef6c00
style RegCheck fill:#e1f5fe,stroke:#0277bdQoder Rules 的使用效果
在鸿蒙端,我们以页面路由服务模块为例,来展示 Qoder Rules 的效果。该模块的核心职责是监听用户的页面跳转行为(包括传统路由和导航组件两种方式),为其附加上下文信息(如页面名称、唯一标识、时间戳),然后通过数据采集机制记录并上报给后端服务。这类模块的测试难点在于,它需要与全局上下文和数据记录器交互来获取实时信息,这使得单元测试需要特别注意资源管理和状态验证。
优化前存在的问题:
- 资源管理缺失,存在内存泄漏风险:测试创建的数据采集对象未正确关闭,缓存中的临时数据未清理,可能导致测试间状态污染和内存泄漏;
- 验证流于表面:只检查了"方法是否能被调用而不抛异常",未验证"数据采集对象是否正确创建"、"时间戳是否正确记录"、"页面切换后资源是否被正确释放";
- 场景覆盖不足:缺少对单例模式、空值边界条件、完整页面生命周期(页面即将出现 → 页面显示 → 页面隐藏)等关键场景的测试;
- 代码规范缺失:保留了空的测试钩子模板代码,命名使用简单前缀格式不符合行为驱动开发风格。
Qoder Rules 的优化点:
- 实现完整的资源生命周期管理:所有创建的数据采集对象在测试结束时正确关闭,缓存中的测试数据被主动清理,确保测试间相互隔离,防止内存泄漏。
- 验证核心数据内容:测试重点从"方法是否被调用"升级为"状态是否正确"。通过检查数据采集对象是否存在、时间戳记录是否有效、页面隐藏后资源是否被清理,确保了业务逻辑的正确性。
- 构筑全面场景覆盖:新增单例模式验证、边界条件测试(空值、部分空值)、服务启停测试、完整页面生命周期测试(传统路由和导航组件两种类型),覆盖了真实使用场景的复杂情况,增强了代码健壮性。
优化前后对比效果参考表格数据:
| 对比维度 | 指标 | 优化前 | 优化后 | 说明 |
| 基础指标 | 测试用例数量 | 13 个 | 23 个 | 新增 10 个关键场景 |
| 代码行数 | 181 行 | 792 行 | 增加功能性测试与注释 | |
| 资源管理 | 数据采集对象生命周期 | ❌ 未关闭 | ✅ 完整关闭与清理 | 防止内存泄漏 |
| 时间缓存清理 | ❌ 无 | ✅ 主动清理 | 测试间隔离 | |
| 数据缓存清理 | ❌ 无 | ✅ 主动清理 | 测试间隔离 | |
| 异常处理方式 | ❌ 无 | ✅ 捕获异常并确保清理 | 确保资源释放 | |
| 测试覆盖 | 单例模式测试 | 0 个 | 1 个 | 验证全局唯一实例 |
| 边界条件测试 | 2 个 | 5 个 | 空值、部分空值场景 | |
| 服务生命周期测试 | 2 个 | 4 个 | 启动、停止、配置禁用 | |
| 页面状态回调测试 | 2 个 | 6 个 | 即将出现/显示/隐藏 全覆盖 | |
| 完整生命周期测试 | 0 个 | 2 个 | 传统路由 + 导航组件 完整流程 | |
| 资源清理验证测试 | 0 个 | 1 个 | 验证页面隐藏时的清理逻辑 | |
| 代码质量 | 命名规范遵循 | ❌ 简单前缀 | ✅ 行为描述式 | 符合 BDD 风格 |
| 冗余代码 | 有空模板代码 | 已移除 | 代码整洁 | |
| 结构规范性 | 基础 | 完整(准备-执行-断言) | 清晰的测试结构 | |
| 类型声明 | 松散 | 严格 | 符合 ArkTS 规范 |
可持续维护策略
为了确保 Qoder Rules 在项目中长期有效并能适应项目的演进,就必须有一套可持续的维护策略,核心思想是,要像管理源代码一样管理 Rules,确保 Rules 的质量、一致性和时效性。可以通过实施以下几点来进行管理:
- 版本化管理:所有 Qoder Rules 存储在代码仓库的 ./qoder/rules 目录下,和源代码一样进行版本管理与代码评审;
- CI/CD 驱动的自动化质量保障:可以在 CI/CD 门禁检查中,添加关于 Qoder Rules 的检查,例如包括
- 行数限制: 编写一个脚本,自动检查 ./qoder/rules 目录下的所有 .mdc 文件,确保所有规则不超过官方限制的 100000 个字符;
- 废弃 API 扫描:维护一个废弃 API 或不推荐写法的清单(例如,Android 规则中的 MockitoAnnotations.initMocks(this))。CI 脚本会扫描规则文件,若发现推荐使用废弃写法的示例,需要报错强制更新;
- 描述完整性检查:对于生效规则为 Agent Requested 的 Rule,强制要求其 description 字段不能为空且有意义,确保 AI 可以准确理解其用途;
- 模版语法校验:在规则中的代码模版是 AI 生成代码的基础,需要保证其正确性,可以编写一个 CI 脚本,提取规则文件中特定语言的代码块(如 Swift,Java,Kotlin),并调用相应的静态分析工具对其进行语法检查。例如,提取 Switt 模版代码并尝试用 swift -syntax-only 进行编译。这能有效防止因模版中的拼写错误而导致 AI 生成大量无法编译的代码。
- 上述所有检查都应整合到项目的 CI 配置文件中(如 .github/workflows/main.yml 或 .gitlab-ci.yml)。可以创建一个名为 lint-qoder-rules 的独立任务,该任务与单元测试、编译等任务并行执行。在代码仓库的保护分支策略中,将 lint-qoder-rules 设置为必须通过的检查项。这样一来,任何不符合规范的规则变更都会被 CI 系统自动拦截,无法合入主干,从而形成一个健壮的、自动化的维护闭环。
总结与展望
本文展示了如何通过具体的指令、模版和约束,将 AI 的能力聚焦于我们的实际需求,让它生成的代码不再是“看起来正确”,而是真正可用且优质,无论是 iOS 端的自动化验证流程,还是 Android 端对框架依赖的严格隔离,这些细节共同构成了一套能显著改善日常开发体验的解决方案。进一步地举一反三,这种模式可以应用到任何具有重复性和规范性的编码任务中,例如:快速创建符合团队代码风格的 UI 控件;为新的业务模块生成基础的数据模型和 service 层代码;批量为老代码添加规范化的文档注释。核心是:凡是能总结出规律和模板的工作,都可以尝试用 Qoder Rules 来自动化。
本文通过 Qoder Rules 展示了如何在开发阶段构筑高质量的单元测试,从源头保证应用的健壮性。然而,应用的质量保障是一个完整的闭环,线上环境的真实用户体验才是最终的试金石。当代码发布上线后,如何精准捕捉性能瓶颈、定位偶现崩溃、洞察用户真实交互体验,就成了新的挑战。本文使用的例子中提到的工程——阿里云用户体验监控(RUM)是一款专为移动应用打造的性能与体验监控利器,它提供了应用崩溃、卡顿、网络错误、页面加载等关键性能指标的实时监控。可以参考接入文档体验使用。相关问题可以加入“RUM 用户体验监控支持群”(钉钉群号: 67370002064)进行咨询。