测试环境搭建:配置 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.2 | JUnit 测试框架基础 | 4.13.2 |
androidx.test:runner:1.5.2 | 测试运行器,管理测试生命周期 | 1.5.2 |
androidx.test:rules:1.5.0 | 测试规则,如 ActivityScenarioRule | 1.5.0 |
androidx.compose.ui:ui-test-junit4:1.6.0 | Compose 测试核心 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.1 | Espresso 基础,用于与 View 系统交互 | 3.5.1 |
androidx.test.ext:junit:1.1.5 | AndroidX 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 —— 白花了两个小时。
核心概念流程图
下面这张图把整个环境搭建的脉络串起来,从创建模块到运行测试,你对照着看:
核心总结:环境搭建就三步——创建模块、加依赖、配运行器。大部分遇坑都出在版本不统一和少了 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,结果调试了两天。