☰
如何为手机AI应用构建测试体系:Off Grid AI三平台(Jest+JUnit+XCTest)测试矩阵实践
2026/9/30 16:33:46 网站建设 项目流程

如何为手机AI应用构建测试体系:Off Grid AI三平台(Jest+JUnit+XCTest)测试矩阵实践

【免费下载链接】OGAMThe Swiss Army Knife of Offline AI. Chat, see, speak, and generate images on your phone or Mac — GGUF LLMs, vision, Whisper speech-to-text, Stable Diffusion, tool calling, and local-network servers. Runs on your CPU, GPU, or NPU. No account, no API key, zero data leaves your device.项目地址: https://gitcode.com/gh_mirrors/of/OGAM

Off Grid AI 是一款运行在手机和 Mac 上的离线 AI 应用,支持 GGUF 大模型聊天、视觉理解、Whisper 语音转文字、Stable Diffusion 图像生成,全程无需账号和 API Key。像它这样的移动 AI 应用,代码横跨 JavaScript、Kotlin、Swift 三层,任何一个平台的疏漏都会导致线上事故——而它的解法是一套覆盖三平台的手机AI测试体系:Jest 管业务逻辑层,JUnit 管 Android 原生模块,XCTest 管 iOS 原生模块,一条命令全部跑完。本文拆解它的测试矩阵设计,帮你建立可复用的测试体系。

一条命令跑完三平台:测试门禁怎么设计

项目把所有平台测试收口到一条命令(见 package.json):

命令平台说明
npm test三平台串行Jest 覆盖 + Android 单测 + iOS 单测
npm run test:androidAndroidgradlew :app:testDebugUnitTest
npm run test:iosiOS调用 scripts/test-ios.sh,自动挑选可用 iPhone 模拟器后执行xcodebuild test

这个设计有三个值得借鉴的细节:

  1. 模拟器不写死型号:Xcode 版本迭代会改名模拟器,脚本按运行时标识动态选择可用的 iPhone,避免 CI 因"设备不存在"而假红。
  2. 测试与 Lint 联动:npm run lint同时跑 ESLint、Android Lint、SwiftLint,代码风格和测试质量在同一道门禁里把关。
  3. 质量平台兜底:npm run sonar接入 SonarQube(sonar-project.properties),持续追踪技术债务。

Jest 层:75% 覆盖率门槛与智能 stub 切换

Jest 是整个体系的主力(jest.config.js),它测的是 React Native 业务逻辑层。两个设计亮点:

① 分层覆盖率门槛,防止"平均数作弊"

global: 语句/分支/函数/行 均 ≥ 75% pro 子模块: 单独分组,同样 ≥ 75% 关键安全模块: 100%(如模型完整性校验、图像生成建议等)

全局 75% 容易被大文件"稀释",所以项目把新增的关键模块单独钉到 100%,例如 imageModelIntegrity.ts 这类负责模型文件字节级校验的模块,任何未覆盖分支都会让 CI 失败。

② 商用子模块缺失时自动降级

Jest 配置会检测pro/子模块是否检出:检出时,音频/MCP 相关测试套件对真实商用包运行;未检出(开源 CI 场景)时,这些套件被忽略并映射到空 stub(proStub.js),保证公开 CI 永远绿色,而私有 CI 又确实测到了真实行为。这是开源+商用混合仓库的经典解法。

测试文件按职责分层组织在__tests__/下:

  • unit/— 工具函数、服务、状态机的纯逻辑测试(100+ 个服务测试)
  • integration/— 挂载真实屏幕、用真实手势驱动的集成测试
  • harness/— 共享测试台架,核心是 nativeBoundary.ts,统一 mock llama、Whisper、扩散模型等原生边界
  • contracts/— 跨平台契约测试,确保 iOS/Android 原生模块行为一致

JUnit 层:用 Kotlin 守住 Android 原生边界

Android 原生模块的测试位于android/app/src/test/java/ai/offgridmobile/,用 JUnit + Kotlin 编写,按功能域分包:

包代表测试守什么
download/DownloadManagerModuleTest.kt模型断点续传、下载完成广播
localdream/LocalDreamModuleTest.ktStable Diffusion 本地图像生成
litert/LiteRTTokenBudgetTest.ktLiteRT 引擎 token 预算
sync/BlobChannelE2ETest.kt局域网大文件加密传输端到端

值得注意 BlobChannelE2ETest.kt:设备间局域网同步涉及 TCP、加密分帧、接口候选筛选,这些在 Jest 层完全摸不到,必须落在 JUnit 层做端到端验证。

XCTest 层:用 Swift 验证 iOS 原生行为

iOS 原生测试集中在 OffgridMobileTests.swift(约 1200 行),风格上很有参考价值——每个断言都指向一个真实缺陷模式:

  • StreamingFileHasherTests:流式 SHA512 校验大文件时,用task_info实测物理内存占用,断言 96MB 文件哈希完成后内存增量 < 32MB——防止"能跑但泄漏"的实现蒙混过关。
  • PDFExtractorModuleTests:动态渲染真实 PDF(单页/多页/空页),断言截断标记和PDF_ERROR错误码。
  • CoreMLDiffusionModuleTests:校验 SD/SDXL 两种模型目录布局,缺分片时返回精确错误信息。
  • BlobReceiveWindowTests:验证加密分帧窗口的最小/最大字节数,保证与 Android 端分帧实现一致。

iOS 端另有 EmbeddingModelBundleTests.swift 守护 RAG 向量嵌入模型的 Bundle 完整性。

测试矩阵:如何让组合爆炸变得可控

这是该项目最值得学习的方法论,完整写在 docs/TEST_MATRIX.md。

离线 AI 应用的 bug 几乎都藏在变体交叉点:LiteRT × 提示词增强、QNN × Android × 全新下载、语音条 × 持久会话 × 重发……单元测试各自全绿,功能在交叉处炸掉。全排列约数万个格子,枚举不可能,项目用三板斧解决:

  1. 旅程测试(Journey):一条真实用户故事横穿多个维度,走真实缝隙(UI 意图 → 服务 → 状态/驻留/引擎 → 回显),只 mock 原生边界,逐步断言终端产物。
  2. Pairwise 两两组合:不测 N 元组合,只保证任意两个维度值至少相遇一次——绝大多数交互缺陷是"对"级别的。
  3. 场景即数据:Scenario是普通对象(平台、内存、引擎、能力、驻留状态、步骤、断言),一个 runner 跑describe.each(scenarios),新增交叉点只加一行,不新写一个文件。

配套的 docs/TEST_PLAN.md 进一步规定了两条硬规则:只测 UI 行为(每个前置状态都必须通过真实手势到达,禁止setState伪造状态)和缝隙必须来自真机抓包(fake 回放的是真机 wire log 里捕获的真实数据形状,不是拍脑袋的 mock)。

真机 E2E:截图即证据

单测全绿不等于真机可用,所以最外层还有一道真机 E2E(npm run e2e:device,见__tests__/device/):

  • 用 Appium/WebDriverAgent 驱动真 Android 与 iPhone,跑 mesh 配对、同步等关键流程;
  • 每步留存截图作为证据,如 meshPairing.e2e.mjs 的截图档案里既有 Android 也有 iOS 双端画面;
  • 真机发现的新缺陷回流到 TEST_PLAN 的 B 系列编号(B1–B33),转化为 Jest 层的对抗性红测,形成"真机发现 → 回归固化"的闭环。

你可以直接抄走的清单

  1. 一条命令跑完所有平台:npm test= Jest 覆盖率 + Gradle 单测 + xcodebuild 模拟器单测。
  2. 覆盖率分层设防:全局 75% 防稀释,关键安全模块 100% 钉死,商用子模块单独分组。
  3. 原生边界必须平台内自测:Jest 摸不到原生,JUnit/XCTest 各守一个平台,契约测试保证双端行为一致。
  4. 交叉点用旅程 + Pairwise 覆盖:bug 在维度交叉处,不在单函数里。
  5. Fake 必须回放真机真实数据形状,而不是猜的结构。
  6. 真机 E2E 留截图,缺陷回流为自动化红测。

参考资料:docs/TEST_MATRIX.md、docs/TEST_PLAN.md、docs/QA_TEST_PLAN.md

【免费下载链接】OGAMThe Swiss Army Knife of Offline AI. Chat, see, speak, and generate images on your phone or Mac — GGUF LLMs, vision, Whisper speech-to-text, Stable Diffusion, tool calling, and local-network servers. Runs on your CPU, GPU, or NPU. No account, no API key, zero data leaves your device.项目地址: https://gitcode.com/gh_mirrors/of/OGAM

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询