测试环境搭建:配置 Compose 测试依赖,创建测试模块,引入必要库

好,咱们开始动真格的了。你要做 Compose 测试,第一件事就是先把环境支棱起来。这部分我踩过的坑还不少,曾经因为少加一个依赖,搞了一整天找不到测试为啥跑不起来——结果就是一行 addTestArtifact 的事。所以这部分咱们一次讲清楚,你跟着走就行。

为什么我建议单独开一个测试模块?

很多项目图省事,直接在 app 模块里写测试。但如果你做的是大型应用,或者有多个团队同时维护,我个人的建议是:创建一个独立的 :test-utils 或 :testing 模块。为什么呢?

  • 隔离编译:测试相关依赖不会污染主模块的 classpath
  • 复用性:测试工具类、自定义 Matcher 可以跨模块共享
  • 清晰度:一眼就知道哪些代码是给测试用的,不是给正式代码的

当然,小项目直接写在 app 模块也没毛病。我这里以独立模块为例,你根据自己情况选一个就行。

创建测试模块

在你的 settings.gradle.kts 里加上一行:

include(":testing")

然后新建一个目录 testing,里面创建 build.gradle.kts。我习惯用 Kotlin DSL,但你用 Groovy 写法也一样,只是语法不同。

接下来重点来了:配置依赖。这里我列出最核心的库,一个都不能少。

核心依赖一览

依赖作用版本示例(请用你项目兼容的最新版)
junit:junit:4.13.2JUnit 测试框架基础4.13.2
androidx.test:runner:1.5.2测试运行器,管理测试生命周期1.5.2
androidx.test:rules:1.5.0测试规则,如 ActivityScenarioRule1.5.0
androidx.compose.ui:ui-test-junit4:1.6.0Compose 测试核心 API(ComposeTestRule 等)1.6.0
androidx.compose.ui:ui-test-manifest:1.6.0提供测试用的 Activity 声明(addTestArtifact)1.6.0
androidx.test.espresso:espresso-core:3.5.1Espresso 基础,用于与 View 系统交互3.5.1
androidx.test.ext:junit:1.1.5AndroidX JUnit 扩展,提供测试方法注解1.1.5

💡 版本号对齐很重要。我曾经因为 ui-test-junit4 和 ui-test-manifest 版本不一致,死活找不到 composeTestRule。后来统一到相同版本就解决了。你最好用 BOM 来管理 Compose 版本:

implementation(platform("androidx.compose:compose-bom:2024.02.00"))
  androidTestImplementation("androidx.compose.ui:ui-test-junit4")
  androidTestImplementation("androidx.compose.ui:ui-test-manifest")

完整 build.gradle.kts 示例

我给一个我常用的模板,你直接抄进去就行:

plugins {
    id("com.android.library")
    id("org.jetbrains.kotlin.android")
}

android {
    namespace = "com.example.testing"
    compileSdk = 34
    defaultConfig {
        minSdk = 21
        testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    }
    compileOptions {
        sourceCompatibility = JavaVersion.VERSION_17
        targetCompatibility = JavaVersion.VERSION_17
    }
    kotlinOptions {
        jvmTarget = "17"
    }
    // 重点:指定测试目标模块
    // 如果你的测试模块用于测试 app 模块,需要这样关联
    targetProjectPath = ":app"
}

dependencies {
    // 必须的 AndroidX 测试库
    androidTestImplementation("junit:junit:4.13.2")
    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")

    // Compose 测试
    val composeBom = platform("androidx.compose:compose-bom:2024.02.00")
    androidTestImplementation(composeBom)
    androidTestImplementation("androidx.compose.ui:ui-test-junit4")
    androidTestImplementation("androidx.compose.ui:ui-test-manifest")

    // 如果是协程测试,你可能还需要
    androidTestImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
}

注意那个 targetProjectPath 属性——它告诉 Gradle,这个测试模块的项目要针对哪个模块跑测试。少了这行,你的测试可能找不到 app 里的 Composable 函数。

配置测试运行器与清单

默认情况下 Gradle 会使用 AndroidJUnitRunner,但你可以在 defaultConfig 里显式指定:

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

这一步不加也不会出错,但我建议你加上,防止未来有别的 runner 被误继承。

另外,ui-test-manifest 这个库会在测试 APK 的清单里自动添加一个 Activity——ComponentActivity 的声明,这样 ComposeTestRule.createAndroidComposeRule() 才能找到要启动的 Activity。如果你用的是旧版 Compose(1.2 之前),还需要手动写一个测试清单文件。现在基本不用了,但你如果发现测试启动时报错 “No Activity found to launch”,回头检查一下这个依赖有没有引入。

验证:写一个最简单的测试

环境搭好没?跑一个空测试就知道了:

package com.example.testing

import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.core.app.ActivityScenario
import org.junit.Test
import org.junit.Rule
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SanityCheckTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @Test
    fun testEnvironmentReady() {
        composeTestRule.onNodeWithText("Hello")
            .assertDoesNotExist()
        // 只要不报错,环境就 OK
        println("✅ 环境搭建成功!")
    }
}

运行这个测试,如果绿条通过,恭喜你,环境搭好了。如果红色失败,不要慌,回去检查依赖版本和 targetProjectPath。我记忆中第一次配的时候,就是忘了加 targetProjectPath,结果测试一直说找不到 app 里的 Composable —— 白花了两个小时。

核心概念流程图

下面这张图把整个环境搭建的脉络串起来,从创建模块到运行测试,你对照着看:

Compose 测试环境搭建流程图 1. 创建测试模块 2. 配置 build.gradle 依赖 3. 指定测试运行器 4. 编写测试代码 5. 运行测试并验证 注意事项 • 依赖版本要一致 • 不要漏了ui-test-manifest • 记得设置targetProjectPath

核心总结:环境搭建就三步——创建模块、加依赖、配运行器。大部分遇坑都出在版本不统一和少了 ui-test-manifest。下次遇到诡异错误,先检查这两点。

避坑指南(我流过的血泪)

  • 依赖版本冲突:我曾经同时引入 espresso-core:3.5.0 和 compose-ui-test:1.4.0,结果运行报 ClassNotFoundException。后来发现是因为 Compose 旧版本用了一个过时的 hamcrest 库。升级到 BOM 2024 后就解决了。
  • 忘记加 targetProjectPath:这是新手的常见坑。如果你单独拉了一个测试模块,不设置这个属性,测试代码里引用 createAndroidComposeRule<MainActivity>() 就会报错“找不到类”。解决办法就是在模块的 build.gradle 里加上 targetProjectPath = ":app"。
  • 模拟器 / 真机 API 版本太低:Compose 测试要求最低 API 21,但有些 ui-test-manifest 的新特性(比如自动添加 Activity)在 API 26+ 上才稳定。我建议你的 CI 设备至少跑 API 28。

⚠️ 重要警告:千万别把 ui-test-junit4 放成 implementation 作用域。它必须使用 androidTestImplementation,否则测试 APK 不会被编译进去,测试时会直接 NoClassDefFoundError。我亲眼见过同事把整个 Compose 测试依赖全写成了 implementation,结果调试了两天。