SuperAPI AI 工具集

configuring-test-dependencies

测试与质量

查看项目

更新于 10-16 07:01

技能介绍

用途

本技能用于为 Jetpack Compose UI 测试配置正确的 Gradle 依赖矩阵。Compose UI 测试在依赖层通常会以三种可预测的方式失败:JUnit4 接口被放在了错误的源集、ui-test-manifest 构件缺失或放在错误的配置上、或主机测试(host test)所需三件套不完整。该技能给出精确的依赖矩阵以及监督它的 lint 警告。后续技能(choosing-test-rule-vs-runtest、setting-up-host-vs-device-tests)都假定依赖已经正确。

适用时机

  • 用户报告 java.lang.RuntimeException: Could not launch activity within 45 seconds. Examined activities: ... androidx.activity.ComponentActivity 或 ActivityNotFoundException。
  • IDE 将 createComposeRule 标记为无法解析,或 import androidx.compose.ui.test.junit4.createComposeRule 显示为红色。
  • Lint 在 build.gradle.kts 某行提示 TestManifestGradleConfiguration(严重级别 WARNING)。
  • 用户想为 Compose 添加 Robolectric / 主机(JVM)测试,询问应依赖哪些构件。
  • 用户想启用 enableAccessibilityChecks(...),不确定该功能由哪个构件提供。

不适用时机

  • 依赖已正确,用户在 createComposeRule() 与 runComposeUiTest { } 之间做选择——使用 choosing-test-rule-vs-runtest。
  • 依赖能编译,但测试运行在错误的源集(test/ 与 androidTest/)——使用 setting-up-host-vs-device-tests。
  • 测试能编译运行但不稳定/超时——从 synchronizing-with-idle 开始。

前置条件

  • 应用了 com.android.application 或 com.android.library 插件的 Android Gradle Plugin。
  • 启用 Compose 的模块(org.jetbrains.kotlin.plugin.compose 插件或 buildFeatures.compose = true)。
  • 测试类路径上存在 JUnit4 依赖(Compose 的 ui-test-junit4 仍使用 JUnit4;JUnit5 需要第三方 Vintage engine 桥接,不在范围内)。

主要能力与工作流程

  1. 判断模块需要哪些测试面。典型 Compose 功能模块需要三个:用于截图/渲染线程/全栈覆盖的仪器测试、用于快速逻辑检查的主机(Robolectric)测试、以及供 createComposeRule() 使用的 manifest 辅助构件。
  2. 在正确的配置上添加依赖。示例:
dependencies {
    // --- Instrumentation tests (src/androidTest/) ---
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    // MUST be debugImplementation
    debugImplementation("androidx.compose.ui:ui-test-manifest")

    // --- Host tests with Robolectric (src/test/) ---
    testImplementation("androidx.compose.ui:ui-test")
    testImplementation("androidx.compose.ui:ui-test-junit4")
    testImplementation("androidx.compose.ui:ui-test-manifest")
    testImplementation("org.robolectric:robolectric:4.13")

    // --- Optional: accessibility validation (API 34+) ---
    androidTestImplementation("androidx.compose.ui:ui-test-junit4-accessibility")
    // Or, when using runComposeUiTest { } (no Rule):
    androidTestImplementation("androidx.compose.ui:ui-test-accessibility")
}

精确的 GA 版本来自 Compose UI BOM 或开发者所选 composeVersion。Robolectric 需独立固定版本——它不随 Compose BOM 发布。

  1. 如果测试因 androidx.activity.ComponentActivity 的 ActivityNotFoundException 失败,几乎可以确定是 manifest 构件问题。该构件会把一个 <activity> 条目合并进测试 APK 的 manifest:
<activity android:theme="@android:style/Theme.Material.Light.NoActionBar"
    android:name="androidx.activity.ComponentActivity" android:exported="true" />

没有该条目,createComposeRule() 与 runComposeUiTest { } 会在启动时崩溃。诊断:确认 ui-test-manifest 是否在依赖列表中;确认它是否在 debugImplementation(主机测试为 testImplementation)。若放在 androidTestImplementation,lint 会告警,且不会把 <activity> 合并进仪器测试运行所针对的宿主 APK。

  1. 通过把依赖移到 debugImplementation 来处理 TestManifestGradleConfiguration lint 警告。该检查会在构件出现在 implementation、api、compileOnly、runtimeOnly、androidTestImplementation、testImplementation 等配置时触发,严重级别 WARNING,快速修复会替换为 debugImplementation。

  2. 判断是否需要 manifest 构件。createComposeRule()(无类型参数)与 runComposeUiTest { }(无类型参数)需要它;当使用 createAndroidComposeRule<MyActivity>() 且自行在测试 manifest 中声明 Activity、或使用 createEmptyComposeRule() 并对已声明 Activity 启动 ActivityScenario 时,不需要它。

  3. 对主机测试,确保三个构件都在 testImplementation。缺少 ui-test-manifest 会抛同样的 ActivityNotFoundException;缺少 ui-test 会出现常见测试 API 符号的链接错误。

  4. 仅在计划调用 enableAccessibilityChecks 时添加无障碍构件:ui-test-accessibility 扩展 ComposeUiTest;ui-test-junit4-accessibility 扩展 ComposeTestRule / AndroidComposeTestRule。两者均 @RequiresApi(34),在 Robolectric 上为空操作。

  5. 同步 Gradle 并重新运行测试。./gradlew :app:connectedDebugAndroidTest(仪器)或 ./gradlew :app:testDebugUnitTest(主机)应能编译并定位到 ComponentActivity。

正误对比模式

ui-test-manifest 配置:

// WRONG
androidTestImplementation("androidx.compose.ui:ui-test-manifest")
// RIGHT
debugImplementation("androidx.compose.ui:ui-test-manifest")

主机测试依赖:

// WRONG:缺少 ui-test-manifest(导致 ActivityNotFoundException)与 ui-test(链接错误)
// RIGHT
testImplementation("androidx.compose.ui:ui-test")
testImplementation("androidx.compose.ui:ui-test-junit4")
testImplementation("androidx.compose.ui:ui-test-manifest")
testImplementation("org.robolectric:robolectric:4.13")

自定义 Activity 需在 src/androidTest/AndroidManifest.xml 中自行声明:

<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <application>
        <activity android:name=".MyHostActivity" android:exported="true" />
    </application>
</manifest>

强制规则

  • 必须把 androidx.compose.ui:ui-test-manifest 放在 debugImplementation(仪器测试)或 testImplementation(主机测试),绝不放 androidTestImplementation、implementation 或 api。
  • 必须让 ui-test-junit4 与导入 createComposeRule / ComposeTestRule 的测试处于同一源集。
  • 必须在测试 APK manifest(src/androidTest/AndroidManifest.xml 或 src/debug/AndroidManifest.xml)中声明任何非 ComponentActivity 的测试宿主。
  • 不得通过 lintOptions { disable("TestManifestGradleConfiguration") } 移除该 lint 检查,应应用快速修复。
  • 不得把 ui-test-manifest 放在 release 配置上,它是纯测试脚手架,会给生产 APK 增加不需要的 <activity> 条目。
  • 推荐使用 Compose BOM 使所有 ui-test-* 构件版本一致;Robolectric 独立固定版本。

验证方法

  • ./gradlew :<module>:connectedDebugAndroidTest 编译运行,不出现 ComponentActivity 的 ActivityNotFoundException。
  • ./gradlew :<module>:lint 不报告 TestManifestGradleConfiguration。
  • ./gradlew :<module>:testDebugUnitTest 在使用 runComposeUiTest { } 或 createComposeRule() 时能编译。
  • 依赖块可见地分离 androidTestImplementation、debugImplementation、testImplementation。
  • 测试 APK manifest 中恰好包含一个 <activity android:name="androidx.activity.ComponentActivity"/> 条目。

参考资料

  • Compose testing setup: https://developer.android.com/develop/ui/compose/testing#setup
  • Compose testing overview: https://developer.android.com/develop/ui/compose/testing
  • Compose UI release notes: https://developer.android.com/jetpack/androidx/releases/compose-ui
  • Compose Multiplatform testing: https://www.jetbrains.com/help/kotlin-multiplatform-dev/compose-test.html