关于 running-instrumented-tests-with-androidjunit4
此技能指南整理 AndroidJUnit4 仪器测试的依赖、Runner 配置、注解和规则,帮助 Android 开发者排查测试启动及配置问题。内容涵盖 Test Orchestrator、运行参数、权限授予和动画控制。
主要功能
- 01配置 AndroidX Test 依赖
- 02设置仪器测试 Runner
- 03使用非弃用 AndroidJUnit4
- 04读取仪器运行参数
- 05配置 Test Orchestrator
- 06授予权限并关闭动画
适用场景
- 01修复仪器测试 Runner 找不到的问题
- 02让 Test Orchestrator 按测试隔离进程
- 03按注解或参数筛选测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ skydoves/ android-testing-skills --skill running-instrumented-tests-with-androidjunit4安装后在 Claude Code 中输入/running-instrumented-tests-with-androidjunit4确认已加载。
详细介绍
使用 AndroidJUnit4 运行插桩测试——正确配置运行器栈
运行器栈配置错误时,插桩测试会在任何断言执行前失败:导入已弃用的 AndroidJUnit4,将 orchestrator 配置在 androidTestImplementation 而不是 androidTestUtil 上,或使用已弃用的 androidx.test.InstrumentationRegistry 而不是 androidx.test.platform.app.InstrumentationRegistry。此技能涵盖准确的依赖项矩阵、运行器 Gradle 配置,以及相关注解和规则。
何时使用此技能
- IDE 将
androidx.test.runner.AndroidJUnit4标记为@Deprecated,或测试可以编译,但会发出弃用警告。 am instrument返回INSTRUMENTATION_FAILED: <pkg>/androidx.test.runner.AndroidJUnitRunner或Test runner not found。- Gradle 中已配置 Test Orchestrator,但测试仍共享同一个插桩进程(orchestrator 被静默禁用)。
- 用户通过
am instrument传入-e size small/-e package com.foo,但测试忽略了这些参数——RunnerArgs未接入。 - 测试需要
ACCESS_FINE_LOCATION/RECORD_AUDIO等权限,而用户正通过adb手动授予权限。 - 用户想跳过低于 API 26 的测试,并正在查找相应注解。
何时不要使用此技能
- 用户正在启动
Activity或驱动生命周期——请参阅../../scenarios/launching-activities-with-activityscenario/SKILL.md。 - 用户正在与 Views 交互——请参阅
../../espresso/writing-espresso-tests/SKILL.md。 - 用户正在驱动系统 UI 或其他应用——请参阅
../../uiautomator/cross-app-tests-with-uiautomator/SKILL.md。 - 用户运行的是 JVM(Robolectric / 纯 JUnit)测试——请参阅
../../../jvm-tests/runner/configuring-junit4-on-android/SKILL.md。 - 用户正在决定要测试什么——请参阅
../../../fundamentals/strategies/applying-testing-strategies/SKILL.md。
前提条件
- Android Gradle Plugin 模块(
com.android.application或com.android.library)。 - 磁盘上有
src/androidTest/源代码集(应能解析./gradlew :module:connectedDebugAndroidTest)。 - 模拟器或实体设备(或 Firebase Test Lab / 托管设备)——运行器无法在 JVM 上执行。
- 测试类路径中包含 JUnit 4(
junit:junit:4.13.2);JUnit 5 需要 Vintage 引擎桥接,不在本文范围内。
工作流
- 1. 在
androidTestImplementation上固定 AndroidX Test 构件版本。 根据docs/CORPUS.mdH.1,这些是规范的 2026 GA 版本:
dependencies {
androidTestImplementation("androidx.test:core:1.7.0")
androidTestImplementation("androidx.test:runner:1.7.0")
androidTestImplementation("androidx.test:rules:1.7.0")
androidTestImplementation("androidx.test.ext:junit:1.3.0")
androidTestImplementation("androidx.test.ext:junit-ktx:1.3.0")
androidTestImplementation("androidx.test.ext:truth:1.7.0")
}
androidx.test.ext:junit 是提供未弃用的 AndroidJUnit4 运行器和未弃用的 ActivityScenarioRule 的构件。androidx.test:runner 仍提供旧版 AndroidJUnit4(已弃用)——切勿从那里导入。请参阅 tasks/research/R1-androidx-test-core.md 第 481-490 行。
- 2. 在模块的
android.defaultConfig中设置testInstrumentationRunner。 运行器的 FQCN 是androidx.test.runner.AndroidJUnitRunner——请注意,这是运行器的类,不同于已弃用的AndroidJUnit4测试运行器注解。摘自tasks/research/R1-androidx-test-core.md第 270-289 行:
android {
defaultConfig {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// Optional: pass `-e key value` args to every run via Gradle
testInstrumentationRunnerArguments["clearPackageData"] = "true"
}
testOptions {
animationsDisabled = true // hermetic — see Pattern below
}
}
- 3. 使用来自
androidx.test.ext.junit.runners的@RunWith(AndroidJUnit4::class)为测试类添加注解。 这是唯一正确的导入方式:
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class LoginActivityTest {
@Test fun loginSucceeds() { /* ... */ }
}
已弃用的 androidx.test.runner.AndroidJUnit4 在 runner-1.7.0/androidx/test/runner/AndroidJUnit4.java:43-44 标记为 @Deprecated。它在运行时仍然有效,但 IDE 会发出警告,代码自动转换工具也会替换它。
- 4. 通过
androidx.test.platform.app.InstrumentationRegistry读取插桩参数。 旧版androidx.test.InstrumentationRegistry(不含platform.app)已标记为@Deprecated,并带有指向规范类的@InlineMe注解——请参阅tasks/research/R1-androidx-test-core.md第 142-153 行:
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.core.app.ApplicationProvider
val instrumentation = InstrumentationRegistry.getInstrumentation()
val args: Bundle = InstrumentationRegistry.getArguments() // -e key value extras
val targetContext: Context = ApplicationProvider.getApplicationContext()
val testContext: Context = instrumentation.context // package context of the test APK
InstrumentationRegistry.getArguments() 会公开 am instrument -e key value 中的 -e 键值对,例如 -e size small -e numShards 4。受支持键的规范列表位于 runner-1.7.0/androidx/test/internal/runner/RunnerArgs.java 第 54-99 行(参见 tasks/research/R1-androidx-test-core.md 第 295-336 行)。
- 5. 使用
androidx.test.filters中的@SmallTest/@MediumTest/@LargeTest标注测试。 配合am instrument -e size small使用,可按速度范围筛选测试。根据该包的 KDoc:SmallTest≤200ms,MediumTest≤1000ms,LargeTest>1000ms。同类注解还有:@FlakyTest、@RequiresDevice、@Suppress。
import androidx.test.filters.SmallTest
import androidx.test.filters.SdkSuppress
@RunWith(AndroidJUnit4::class)
@SmallTest
class LoginViewModelTest { /* ... */ }
@Test
@SdkSuppress(minSdkVersion = 26)
fun usesApi26OnlyApi() { /* ... */ }
@SdkSuppress(minSdkVersion, maxSdkVersion, excludedSdks, codeName) 位于 runner-1.7.0/androidx/test/filters/SdkSuppress.java:39-58。超出 API 范围的测试会被跳过(假设失败,退出代码为 -4),而非失败。
- 6. 将 Test Orchestrator 添加到
androidTestUtil,而非androidTestImplementation。 这是 runner 堆栈中最常见的单项配置错误。Test Orchestrator 会在各自独立的插桩进程中运行每个@Test,因此崩溃只会影响该测试;此外,还可选择在测试之间设置clearPackageData:
dependencies {
androidTestUtil("androidx.test:orchestrator:1.6.1") // installs orchestrator APK on device
androidTestUtil("androidx.test:services:1.6.0") // required for clearPackageData
}
android {
testOptions {
execution = "ANDROIDX_TEST_ORCHESTRATOR"
}
defaultConfig {
testInstrumentationRunnerArguments["clearPackageData"] = "true"
}
}
androidTestUtil 是一种特殊的 AGP 配置,会在运行测试前于设备上安装辅助 APK。将 orchestrator 放入 androidTestImplementation 虽然可以编译,但不会有任何提示且不执行任何操作,测试仍会在单个共享进程中运行。参见 tasks/research/R1-androidx-test-core.md 第 683-687 行。
- 7. 使用
GrantPermissionRule.grant(...)授予运行时权限,而非使用adb shell pm grant。 该规则随androidx.test:rules一同提供,并在测试类运行期间授予权限:
import androidx.test.rule.GrantPermissionRule
import org.junit.Rule
@get:Rule
val permissionRule: GrantPermissionRule = GrantPermissionRule.grant(
android.Manifest.permission.ACCESS_FINE_LOCATION,
android.Manifest.permission.RECORD_AUDIO,
)
该规则实现在 rules-1.7.0/androidx/test/rule/GrantPermissionRule.java 中。在 API 23+ 上,它会使用 UiAutomation.grantRuntimePermission;在较旧的设备上,权限必须已在清单中授予(此规则不执行任何操作)。
-
8. 在无外部干扰的运行中禁用动画。
testOptions { animationsDisabled = true }会在测试运行期间将window_animation_scale、transition_animation_scale和animator_duration_scale设为0,随后在清理时恢复之前的值。否则,点按对焦、波纹效果和 Activity 转场都可能与断言发生竞争。 -
9. (可选)使用
@Rule(order = N)对多个@Rule排序。 顺序号较小的规则会先作为外层规则执行。Hilt 要求将@HiltAndroidRule设为order = 0:
@get:Rule(order = 0) val hiltRule = HiltAndroidRule(this)
@get:Rule(order = 1) val activityRule = ActivityScenarioRule(LoginActivity::class.java)
- 10. 运行。 在主机上执行:
./gradlew :app:connectedDebugAndroidTest
# or via adb directly:
adb shell am instrument -w -r \
-e size small \
-e clearPackageData true \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
要让退出代码有意义,必须使用 -w(等待)。没有它,即使测试失败,$? 也会是 0。参见 docs/CORPUS.md I.5。
模式
模式:错误 vs 正确——AndroidJUnit4 导入
// WRONG
import androidx.test.runner.AndroidJUnit4 // @Deprecated since androidx.test:runner 1.x
@RunWith(AndroidJUnit4::class)
class FooTest
// WRONG because: this class is @Deprecated at runner-1.7.0/.../AndroidJUnit4.java:43-44.
// The IDE flags it; codemods replace it; the doc explicitly redirects to ext.junit.
// RIGHT
import androidx.test.ext.junit.runners.AndroidJUnit4
@RunWith(AndroidJUnit4::class)
class FooTest
模式:错误 vs 正确——InstrumentationRegistry 导入
// WRONG
import androidx.test.InstrumentationRegistry // @Deprecated, every member @InlineMe'd
val ctx = InstrumentationRegistry.getTargetContext() // returns target package context, NOT the application
// WRONG because: monitor-1.8.0/androidx/test/InstrumentationRegistry.java:34 is @Deprecated.
// Use androidx.test.platform.app.InstrumentationRegistry + ApplicationProvider.
// RIGHT
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.core.app.ApplicationProvider
val instrumentation = InstrumentationRegistry.getInstrumentation()
val ctx: Context = ApplicationProvider.getApplicationContext()
模式:错误 vs 正确——Test Orchestrator 配置(最常见的配置错误)
// WRONG
dependencies {
androidTestImplementation("androidx.test:orchestrator:1.6.1")
}
android.testOptions.execution = "ANDROIDX_TEST_ORCHESTRATOR"
// WRONG because: orchestrator must be installed as a separate APK on the device.
// `androidTestImplementation` puts it on the test APK classpath instead, where it does
// nothing. Tests still run in one shared process. No error, just silent inactivation.
// RIGHT
dependencies {
androidTestUtil("androidx.test:orchestrator:1.6.1")
androidTestUtil("androidx.test:services:1.6.0") // required for clearPackageData
}
android.testOptions.execution = "ANDROIDX_TEST_ORCHESTRATOR"
模式:通过 RunnerArgs 在运行时筛选测试
# Run a single method
adb shell am instrument -w -r \
-e class com.example.LoginActivityTest#loginSucceeds \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
# Filter by size annotation
adb shell am instrument -w -r -e size small com.example.app.test/androidx.test.runner.AndroidJUnitRunner
# Shard across N runners (CI fan-out)
adb shell am instrument -w -r -e numShards 4 -e shardIndex 0 \
com.example.app.test/androidx.test.runner.AndroidJUnitRunner
受支持的 -e 键完整列表位于 runner-1.7.0/androidx/test/internal/runner/RunnerArgs.java:54-99(class、package、notClass、size、annotation、notAnnotation、numShards、shardIndex、clearPackageData、coverage、debug、listener 等)。若要在测试中读取这些参数,请使用 InstrumentationRegistry.getArguments()。
强制规则
- 必须在
@RunWith(...)中使用androidx.test.ext.junit.runners.AndroidJUnit4。androidx.test.runner.AndroidJUnit4形式已标记为@Deprecated。 - 必须使用
androidx.test.platform.app.InstrumentationRegistry。不带包名段platform.app的androidx.test.InstrumentationRegistry已标记为@Deprecated。 - 必须将
androidx.test:orchestrator添加到androidTestUtil,绝不能添加到androidTestImplementation。放在错误的配置项中会静默失败。 - 必须设置
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"(这里指 Runner 类——它未弃用,只有测试 Runner 注解已弃用)。 - 必须为
am instrument传入-w,这样退出代码才能反映测试结果。不加此选项时,$?没有意义。 - 不得调用
Thread.sleep来等待 instrumentation 生命周期(onCreate、onStart)。请使用ActivityScenario.moveToState(参见../../scenarios/launching-activities-with-activityscenario/SKILL.md)或IdlingResource。 - 不得在测试中通过原始的
adb shell pm grant授予权限——请使用GrantPermissionRule.grant(...),这样权限授予的范围仅限于测试类,并且结束后能干净地撤销。 - 不得使用
@Rule public ActivityTestRule——它已标记为@Deprecated。请使用@get:Rule val rule = ActivityScenarioRule(...)。 - **建议:**为每个 instrumentation 测试类添加
@SmallTest/@MediumTest/@LargeTest注解,以便 CI 按大小分片筛选。 - **建议:**即使个别测试看起来不需要,也要保留
testOptions.animationsDisabled = true;波纹效果或转场出现间歇性故障时,会悄无声息地破坏其他测试。
验证
-
./gradlew :<module>:connectedDebugAndroidTest运行时不会出现Test runner not found或INSTRUMENTATION_FAILED。 - 没有源文件导入
androidx.test.runner.AndroidJUnit4或androidx.test.InstrumentationRegistry(旧路径)。 -
grep -r "androidTestImplementation.*orchestrator" build.gradle*没有返回任何结果——orchestrator 应添加到androidTestUtil。 -
adb shell am instrument -w -r -e size small <pkg>.test/androidx.test.runner.AndroidJUnitRunner在测试失败时返回非零退出代码。 - 如果启用了 orchestrator,
adb logcat | grep AndroidTestOrchestrator会显示每个测试的进程启动情况。 - 模块的
android块中设置了testOptions.animationsDisabled = true。 - 测试所需的任何运行时权限都有对应的
@get:Rule val rule = GrantPermissionRule.grant(...)(而不是手动运行adb shell pm grant)。
参考资料
- Android Developers — AndroidJUnitRunner 概览:https://developer.android.com/training/testing/instrumented-tests/androidx-test-libraries/runner
- Android Developers — Test Orchestrator:https://developer.android.com/training/testing/instrumented-tests/androidx-test-libraries/runner#use-android
- AndroidX Test 发布说明:https://developer.android.com/jetpack/androidx/releases/test
runner-1.7.0/androidx/test/runner/AndroidJUnit4.java第 41-44 行 —@Deprecated public final class AndroidJUnit4 extends Runner。junit-1.3.0/androidx/test/ext/junit/runners/AndroidJUnit4.java第 49 行 — 当前未弃用的 Runner;在 JVM 上委托给 Robolectric,在设备上委托给AndroidJUnit4ClassRunner。runner-1.7.0/androidx/test/runner/AndroidJUnitRunner.java第 270-372 行 —am instrument调用的 Runner 类;生命周期和 orchestrator 等待逻辑。runner-1.7.0/androidx/test/internal/runner/RunnerArgs.java第 54-99 行 — Runner 接受的所有-e键的权威列表。monitor-1.8.0/androidx/test/InstrumentationRegistry.java第 34 行 —@Deprecated的旧版注册表;每个成员都通过@InlineMe指向 platform.app 形式。monitor-1.8.0/androidx/test/platform/app/InstrumentationRegistry.java— 当前权威注册表。rules-1.7.0/androidx/test/rule/GrantPermissionRule.java第 1-100 行 —static GrantPermissionRule grant(String...)。runner-1.7.0/androidx/test/filters/SdkSuppress.java第 39-58 行 —minSdkVersion/maxSdkVersion/excludedSdks/codeName。tasks/research/R1-androidx-test-core.md— Runner / test-core 深入分析(Runner 部分见第 269-740 行;关于两个AndroidJUnit4引发的混淆见第 481-490 行)。docs/CORPUS.md第 H 节 — instrumentation 库坐标和弃用表。- 同类技能:
../../managed-devices/running-tests-on-gradle-managed-devices/SKILL.md— 在 Gradle 配置、启动和关闭的模拟器上运行这些测试(可在 CI 中复现)。 - 跨集合:
../../../adb/tests/running-instrumented-tests-via-adb/SKILL.md— 通过adb shell am instrument -w -r直接调用 Runner。 - 跨集合:
../../../platform/legacy/migrating-from-android-test-classes/SKILL.md— 如果模块仍使用旧版android.test.*类 /InstrumentationTestRunner,请先将其迁移到此 Runner 技术栈。