【问题标题】:How to enter text in Jetpack compose TextField through UI tests?如何通过 UI 测试在 Jetpack 中输入文本 compose TextField?
【发布时间】:2021-03-17 14:45:42
【问题描述】:

在 Jetpack compose 中,我有一个 TextField,我正在尝试编写 Espresso UI 测试。
我没有找到如何在 TextField 中输入文本,请问有什么想法吗?

TextField(
    value = textState.value,
    modifier = Modifier.fillMaxWidth(),
    onValueChange = {
        textState.value = it
        apiServiceCall(textState.value.text)
    },
    keyboardOptions = KeyboardOptions(
        capitalization = KeyboardCapitalization.Sentences)
    ),
)

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

@Test
fun enterTextAndMakeServiceCall() {
    ActivityScenario.launch(MainActivity::class.java)

    // TODO: Enter text inside the TextField
    composeTestRule.onNode(hasText(getString(R.string.result)))
}

【问题讨论】:

    标签: android android-espresso android-jetpack ui-testing android-jetpack-compose


    【解决方案1】:

    我首先在我要测试的可组合对象上设置testTag 修饰符:

    const val MY_TEXTFIELD_TAG = "myTextFieldTag"
    
    TextField(
        value = textState.value,
        modifier = Modifier.fillMaxWidth().testTag(MY_TEXTFIELD_TAG),
        onValueChange = {
            textState.value = it
        },
        keyboardOptions = KeyboardOptions(capitalization = KeyboardCapitalization.Sentences),
    )
    

    然后从您的测试中,您可以像这样设置和检查值:

    @Test
    fun setAndCheckTheTextFieldValue() {
        ActivityScenario.launch(MainActivity::class.java)
        val resultText = "result"
    
        // Sets the TextField value
        composeTestRule.onNodeWithTag(MY_TEXTFIELD_TAG).performTextInput(resultText)
    
        // Asserts the TextField has the corresponding value
        composeTestRule.onNodeWithTag(MY_TEXTFIELD_TAG).assert(hasText(resultText))
    }
    

    更新:

    我最近使用的另一种方法是改用contentDescription

    假设您有一个 TextField,其内容描述与此类似(为简单起见,此示例未使用状态提升):

    @Composable
    fun MyTextField() {
        val textState = remember { mutableStateOf(TextFieldValue()) }
        val textFieldContentDescription = stringResource(id = R.string.text_field_content_description)
        TextField(
            value = textState.value,
            modifier = Modifier
                .fillMaxWidth()
                .semantics { contentDescription = textFieldContentDescription },
            onValueChange = {
                textState.value = it
            },
        )
    }
    

    测试可能是这样的:

    @get:Rule
    val composeTestRule = createComposeRule()
    
    @Test
    fun setAndCheckTheTextFieldValue() {
        lateinit var textFieldContentDescription: String
        composeTestRule.setContent {
            textFieldContentDescription = stringResource(id = R.string.text_field_content_description)
            MaterialTheme {
                MyTextField()
            }
        }
        val resultText = "result"
    
        // Sets the TextField value
        composeTestRule.onNodeWithContentDescription(textFieldContentDescription).performTextInput(resultText)
    
        // Asserts the TextField has the corresponding value
        composeTestRule.onNodeWithContentDescription(textFieldContentDescription).assert(hasText(resultText, ignoreCase = true))
    }
    

    这样,通过内容描述,应用程序也更易于访问。

    【讨论】:

    • 我不认为将测试代码添加到生产代码库中是一个好主意。相反,我会使用:composeTestRule.onNodeWithText(text = "result").
    • 但是如果它是一个输入,在添加它之前你没有任何测试“结果”,你首先需要知道它的元素。
    • 我已经更新了答案,添加了一个使用 contentDescription 的示例。这样您就不必在生产代码库中添加此标签,并且您无需依赖任何先前设置的文本,同时提高了代码的可访问性。
    【解决方案2】:

    你可以通过nodeText找到你需要在label属性中搜索字符串

    composeTestRule.onNodeWithText("user").performTextInput("userCred")
    

    这将找到该 Textfield 并输入文本“userCred”。

    此解决方案仅在您没有与该字符串匹配的任何其他文本时才有效。

    【讨论】:

      猜你喜欢
      • 2021-10-01
      • 2023-01-16
      • 2022-11-21
      • 1970-01-01
      • 2022-11-10
      • 2021-11-07
      • 2016-01-23
      • 2021-09-20
      • 1970-01-01
      相关资源
      最近更新 更多