Compose 中 UI 测试

756 阅读2分钟

在 Jetpack Compose 中,编写 UI 测试是确保用户界面按预期行为运行的重要部分。Compose 提供了一组强大的工具和 API 来进行 UI 测试,包括 ComposeTestRulecreateComposeRuleComposeContentTestRule。这些工具允许开发者编写健壮的测试用例,以验证 UI 元素的行为和交互。

1. 测试环境设置

首先,需要在项目的 build.gradle 文件中添加必要的依赖项:

dependencies {
    // Compose UI 测试
    androidTestImplementation "androidx.compose.ui:ui-test-junit4:<compose_version>"
    debugImplementation "androidx.compose.ui:ui-test-manifest:<compose_version>"
}

2. 创建测试类

创建一个测试类来编写 UI 测试用例。通常,这些测试类位于 src/androidTest/java 目录下。

import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.test.*
import androidx.compose.ui.test.junit4.createComposeRule
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import org.junit.Rule
import org.junit.Test

class MyComposeUITests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun testButtonClick() {
        composeTestRule.setContent {
            MyComposable()
        }

        composeTestRule.onNodeWithText("Click Me").performClick()
        composeTestRule.onNodeWithText("Clicked!").assertExists()
    }
}

3. 编写可测试的 Composable

创建一个简单的 Composable 函数用于测试。在这个示例中,当按钮被点击时,文本内容会发生变化。

@Composable
fun MyComposable() {
    var clicked by remember { mutableStateOf(false) }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {
        Button(onClick = { clicked = true }) {
            Text(if (clicked) "Clicked!" else "Click Me")
        }
    }
}

@Preview(showBackground = true)
@Composable
fun PreviewMyComposable() {
    MyComposable()
}

4. 使用 Compose 测试 API

以下是 Compose 测试 API 的一些常用功能:

  • setContent:设置需要测试的 Composable 内容。
  • onNodeWithText:查找包含指定文本的节点。
  • performClick:模拟点击事件。
  • assertExists:断言节点存在。
  • assertIsDisplayed:断言节点显示在屏幕上。
  • onRoot:获取根节点。
  • onNodeWithTag:通过标签查找节点(需要配合 Modifier.testTag 使用)。

5. 更复杂的示例

以下是一个更复杂的示例,展示了如何处理输入框和列表的测试。

@Composable
fun SimpleForm() {
    var text by remember { mutableStateOf("") }
    val items = remember { mutableStateListOf<String>() }

    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(16.dp)
    ) {
        TextField(
            value = text,
            onValueChange = { text = it },
            modifier = Modifier.testTag("TextField"),
            label = { Text("Enter text") }
        )
        Spacer(modifier = Modifier.height(8.dp))
        Button(
            onClick = {
                if (text.isNotEmpty()) {
                    items.add(text)
                    text = ""
                }
            },
            modifier = Modifier.testTag("AddButton")
        ) {
            Text("Add")
        }
        Spacer(modifier = Modifier.height(16.dp))
        items.forEach { item ->
            Text(item)
        }
    }
}

@Preview(showBackground = true)
@Composable
fun PreviewSimpleForm() {
    SimpleForm()
}

class SimpleFormUITests {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun testAddItemToList() {
        composeTestRule.setContent {
            SimpleForm()
        }

        // 输入文本
        composeTestRule.onNodeWithTag("TextField").performTextInput("Test Item")

        // 点击按钮
        composeTestRule.onNodeWithTag("AddButton").performClick()

        // 验证文本是否添加到列表中
        composeTestRule.onNodeWithText("Test Item").assertExists()
    }
}

代码解释

  1. SimpleForm:一个简单的表单,包括一个输入框和一个按钮。用户可以输入文本并将其添加到列表中。
  2. Modifier.testTag:为组件添加标签,方便在测试中查找。
  3. SimpleFormUITests:测试类,包含一个测试用例 testAddItemToList,用于验证输入框和按钮的交互。
  4. performTextInput:模拟文本输入。
  5. performClick:模拟点击事件。
  6. assertExists:断言元素存在。

总结

Jetpack Compose 提供了强大的测试工具,帮助开发者编写健壮的 UI 测试。通过使用 ComposeTestRule 和相关 API,可以轻松地模拟用户交互、查找 UI 元素并进行断言。这些测试不仅提高了代码质量,还确保了用户界面的稳定性和可靠性。以上示例展示了如何编写和运行 Compose UI 测试,您可以根据自己的需求进行扩展和应用。