4. AndroidX Test库概述:核心依赖、测试运行器、Instrumentation与本地测试区别

做系统应用的回归测试,第一关就是搞清楚测试框架怎么选。AndroidX Test 是 Google 官方主推的测试库,说白了就是帮你绕过那些坑爹的系统级限制。

我记得刚开始接触 Android 测试时,还在用 JUnit 3 和旧版的 InstrumentationTestRunner。后来项目迁移到 AndroidX,发现整个测试体系完全变了样。嗯,今天我们就来理一理这些核心组件。

4.1 核心依赖:你最少需要引入哪些库

一个典型的系统应用回归测试,Gradle 里至少要加这几样东西。别贪多,也别漏掉。

// 注意:版本号根据实际项目调整
androidTestImplementation 'androidx.test:core:1.5.0'
androidTestImplementation 'androidx.test:runner:1.5.2'
androidTestImplementation 'androidx.test:rules:1.5.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'

每一样都有它的活:

  • core —— 提供了 ApplicationProvider、测试生命周期回调。你想想看,没有它,连获取 Context 都得自己写反射。
  • runner —— 负责把测试用例跑在设备上。它是整个 Instrumentation 测试的调度中枢。
  • rules —— 帮你管理 Activity 启动、权限授予等操作。我习惯用 ActivityScenarioRule 替代老旧的 ActivityTestRule。
  • ext:junit —— 桥接 JUnit4/5,提供 @RunWith(AndroidJUnit4.class)。
  • espresso-core —— UI 操作和断言。系统应用里经常要跨进程断言,它比 UiAutomator 更轻量。
避坑指南:我曾经过度依赖 androidx.test:monitor,后来发现它底层已经合并到 core 里了。加上反而导致版本冲突。引入前先查一次官网的依赖树。

4.2 测试运行器:AndroidJUnitRunner 到底干了啥

AndroidJUnitRunner 不仅仅是“启动测试”那么简单。它做了三件核心的事:

  1. 创建 Instrumentation 实例,注入 Application 和 Activity 的上下文。
  2. 解析 @RunWith 注解,找到正确的测试执行逻辑。
  3. 把每个测试用例放到绑定的进程里运行,并收集结果。

在系统应用的回归场景里,经常需要自定义 Runner。比如我们项目里有一个 SystemAppTestRunner,继承自 AndroidJUnitRunner,额外加了 SELinux 权限配置。你只要在 build.gradle 里指定:

android {
    defaultConfig {
        testInstrumentationRunner "com.example.SystemAppTestRunner"
    }
}
如果你用 AndroidX Test 的默认 Runner,记得在 Manifest 里声明 <instrumentation>。不然测试进程根本进不去。我遇到过好几次这种低级错误。

4.3 Instrumentation 测试 vs 本地测试:到底差在哪

很多新人会混淆这两个概念。我简单列个对比,你就明白了。

对比维度 Instrumentation 测试 本地测试 (JVM Test)
运行位置 真机 / 模拟器 开发机 JVM
可访问系统 API 完全访问(需签名) 只能 mock
执行速度 慢(需安装 APK) 快(毫秒级)
需要 Android 上下文 有 无
适合场景 系统 UI、跨进程、真实 HAL 纯逻辑、数据层、Unit 测试

为什么系统应用回归更依赖 Instrumentation 测试?

  • 因为很多系统 API 是隐藏的,本地测试根本调不动。
  • 因为测试需要和系统服务交互,比如 ActivityManager、WifiManager,只有真机上才真实。
  • 因为回归要求高可信度,mock 出来的东西不可靠。

但也不要全盘抛弃本地测试。我自己的习惯是:逻辑层用本地测试快速验证,系统交互层用 Instrumentation 测试做回归。两种并行,效率最高。

注意:Instrumentation 测试会真正安装 APK 并运行,因此测试 APK 和被测 APK 必须共享同一个进程或签名。系统应用通常 platform 签名,测试包也必须同样签名。否则会报 SecurityException。踩过这个坑的人应该不少。

4.4 一张图看懂 AndroidX Test 库结构

下面这个图,把核心组件、运行流程和两种测试类别串在一起。你看一遍就能回忆起整个体系的脉络。

AndroidX Test 库结构总览 本地测试 运行于 JVM 不需要设备 依赖:JUnit + Mockito 速度:快(毫秒级) 常用在:纯逻辑、数据层 Instrumentation 测试 运行于真机/模拟器 可访问系统 API 依赖:AndroidX Test 库 速度:慢(需安装 APK) 常用在:UI、系统交互 核心依赖库 core runner rules ext:junit espresso-core 共同依赖:monitor 运行器:AndroidJUnitRunner 系统应用回归测试:以 Instrumentation 测试为主,本地测试辅助逻辑验证

4.5 归纳总结:什么时候该用哪个

说一千道一万,你只需要记住两条原则:

  • 如果你要测试的代码不依赖 Android 框架(比如数据解析、工具类),优先写本地测试。运行快、不依赖设备。
  • 如果你是做系统应用的回归,涉及 Activity 跳转、系统服务调用、权限弹窗、跨进程通信,必须上 Instrumentation 测试。别省这一步,否则线上出问题你根本猜不到原因。
我个人的建议是:在一个系统项目里,用 70% Instrumentation 测试 + 30% 本地测试 的比例来分配。本地测试跑在 CI 的快速检查阶段,Instrumentation 测试跑在夜间回归。这样既保速度又保质量。