用途
本技能用于在 Android 仪器化测试中启动、驱动和销毁 Activity,基于 ActivityScenario 及其 JUnit4 封装 ActivityScenarioRule。它是已废弃 ActivityTestRule 的规范替代方案,提供线程安全、生命周期感知的 Activity 句柄。
适用时机
- 新建需要 Activity 宿主的仪器化测试。
- 从已废弃的 ActivityTestRule 迁移并寻找替代方案。
- 测试因测试 APK 清单缺少 Activity 而报 ActivityNotFoundException。
- recreate() 测试"丢失"状态,需要调试 remember 与 rememberSaveable 的差异。
- 向 UI 线程投递操作时测试死锁(onActivity 从错误线程调用)。
- 测试调用 setResult(...) + finish() 并希望读取 Activity.RESULT_*。
主要能力
- 启动入口:
ActivityScenario.launch(基于类的启动)、launchActivity<T>()(Kotlin reified 扩展)、带显式 Intent 的启动、以及供 setResult + finish 场景使用的launchActivityForResult。launch 会阻塞调用方直到 Activity 到达 RESUMED。 - 生命周期驱动:通过
moveToState(Lifecycle.State.*)在 CREATED、STARTED、RESUMED、DESTROYED 间切换。DESTROYED 为终态,到达后不可回退。 - 配置变更模拟:
recreate()执行 onSaveInstanceState、销毁并重建 Activity、再执行 onRestoreInstanceState。通过 rememberSaveable / SavedStateHandle / Bundle 存储的状态可保留,普通 remember 与裸 var 字段不会。 - UI 线程操作:
onActivity { activity -> }在 UI 线程执行并阻塞测试线程直至完成,是直接操作字段和视图的唯一合法方式。 - 结果读取:通过
scenario.result读取 Activity.RESULT_*,仅对 launchActivityForResult 启动且已 setResult + finish 的场景有效。 - JUnit4 封装:
ActivityScenarioRule在 before 调用 launch、在 after 调用 close。 - 规则排序:与 Hilt 配合时,Hilt 置于最外层(order = 0),ActivityScenarioRule 使用 order = 1 或更高。
使用方式
依赖(Prerequisites)
androidTestImplementation("androidx.test:core:1.7.0")(提供 androidx.test.core.app.ActivityScenario)androidTestImplementation("androidx.test.ext:junit:1.3.0")(提供 androidx.test.ext.junit.rules.ActivityScenarioRule)androidTestImplementation("androidx.test:runner:1.7.0")与testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"- 测试 Activity 需在 src/androidTest/AndroidManifest.xml、src/debug/AndroidManifest.xml 或生产清单中声明。
关键规则
- 必须从
androidx.test.ext.junit.rules导入 ActivityScenarioRule;androidx.test.rule包不包含它。 - 新测试不得使用 ActivityTestRule(已废弃)。
- 不得从主线程调用 launch、moveToState 或 close,否则会因 instrumentation barrier 永不触发而死锁。
- 不得在 lambda 之外保存 onActivity 返回的 activity 引用。
- 不得依赖 Settings.Global.ALWAYS_FINISH_ACTIVITIES 强制 recreation,应使用 scenario.recreate()。
- 自定义测试 Activity 必须开发者在清单中声明,ui-test-manifest 仅贡献 androidx.activity.ComponentActivity。
- 必须调用 moveToState(Lifecycle.State.DESTROYED) 或 close(),或使用自动 close 的 ActivityScenarioRule。
关闭方式:使用 ActivityScenarioRule 时 JUnit 自动调用 close();临时启动时可用 Kotlin 的 use { }(scenario 实现 java.io.Closeable)。close() 会将 Activity 驱动到 DESTROYED 且是幂等的。
适用场景
适用于 Android 仪器化测试中需要 Activity 宿主的所有场景,尤其是需要精细化控制生命周期、模拟配置变更、验证状态恢复或读取 Activity 结果的测试。
限制
- 宿主为 Fragment 时不适用(应使用 FragmentScenario)。
- 宿主为 androidx.activity.ComponentActivity 的 Compose 测试不适用(createComposeRule() 已封装 scenario)。
- 需要与系统 UI 或其他应用交互时不适用(应使用 UiAutomator)。
- 不支持主线程直接调用 launch/moveToState/close。
- 不遵守 "Don't keep activities" 设置,无法通过该方式测试 recreation。
- 具体收费、价格、平台等信息资料中暂未提供。