🧪 Compose 单元测试

环境搭建 · 从入门到实战 📘 第2章

⚡ 在 Android 项目中配置 Compose 测试依赖,并深入对比 JUnit4 与 JUnit5 的选择策略。

🎯 中小学生色系 · 轻松掌握
📦

Compose 测试依赖速览

在 build.gradle.kts (Module :app) 中添加以下核心依赖:

// Compose 测试基石 (必须)
androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.8")

// 可选:Compose 测试工具 (断言、语义等)
androidTestImplementation("androidx.compose.ui:ui-test:1.6.8")

// 调试辅助 (无需额外配置)
debugImplementation("androidx.compose.ui:ui-test-manifest:1.6.8")
⚖️

JUnit4 与 JUnit5 的选择

对比维度 JUnit4 (传统) JUnit5 (现代)
Compose 原生支持 ✅ 官方一等公民 ⚠️ 需额外适配 (vintage + 扩展)
注解风格 @Test, @Before, @Rule @Test, @BeforeEach, @ExtendWith
参数化测试 @RunWith(Parameterized::class) @ParameterizedTest (原生优雅)
ComposeTestRule 集成 直接使用 @get:Rule 需 @RegisterExtension 或手动规则
社区趋势 稳定,存量项目多 新项目首选,更现代

🧭 推荐选择策略

  • JUnit4 — 如果你希望开箱即用、与 Compose 测试深度绑定、避免额外配置,JUnit4 是最稳妥的路径。
  • JUnit5 — 如果你追求现代测试特性(嵌套、动态、参数化),并且愿意添加 junit-vintage-engine 或使用 android-junit5 插件。
  • 混合模式 — 可以在同一项目中同时保留 JUnit4 与 JUnit5,但建议统一风格。
🧩

JUnit5 集成架构 (含 Compose)

Compose 测试 ui-test-junit4 JUnit5 引擎 junit-jupiter-api Vintage 桥接 junit-vintage-engine 💡 使用 JUnit5 + Vintage 可同时运行 JUnit4 风格 Compose 规则 android-junit5 插件自动管理依赖

📄 build.gradle.kts (JUnit5 配置示例)

plugins {
    id("de.mannodermaus.android-junit5") version "1.11.2.0"
}

android {
    // ...
    testOptions {
        unitTests.all { useJUnitPlatform() }
    }
}

dependencies {
    // Compose 测试 (仍然依赖 JUnit4 规则, 但通过 vintage 桥接)
    androidTestImplementation("androidx.compose.ui:ui-test-junit4:1.6.8")

    // JUnit5 核心
    androidTestImplementation("org.junit.jupiter:junit-jupiter-api:5.10.2")
    androidTestRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.10.2")

    // 桥接: 让 JUnit4 规则 (如 ComposeTestRule) 在 JUnit5 中运行
    androidTestImplementation("org.junit.vintage:junit-vintage-engine:5.10.2")
}
✨

环境验证 · 快速上手

✅ JUnit4 快速测试

@RunWith(AndroidJUnit4::class)
class ExampleTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun myTest() {
        composeTestRule.setContent { Text("Hello") }
        composeTestRule.onNodeWithText("Hello").assertExists()
    }
}

✅ JUnit5 风格 (Vintage)

class JUnit5StyleTest {
    @RegisterExtension
    val composeTestRule = createComposeRule()

    @Test
    fun composeTest() {
        composeTestRule.setContent { Text("JUnit5") }
        composeTestRule.onNodeWithText("JUnit5").assertIsDisplayed()
    }
}