Espresso - onClick 在 Compose AndroidView 内的嵌套 ButtonView 上执行时不起作用

sko*_*kon 6 android kotlin android-espresso android-jetpack-compose

我正在使用 Espresso 来测试在 AndroidView 可组合项中具有嵌套 ButtonView 的 Compose 屏幕。但是调用Espresso.onView(ViewMatchers.withText("Click me")).perform(ViewActions.click())不起作用,并且运行测试时不会调用 onClick 回调,导致检查是否text已更新的断言失败。

我的撰写/测试依赖项是

implementation "androidx.compose.ui:ui:1.1.1"
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.1.1"
debugImplementation "androidx.compose.ui:ui-tooling:1.1.1"
debugImplementation "androidx.compose.ui:ui-test-manifest:1.1.1"
Run Code Online (Sandbox Code Playgroud)

我的混合 Compose 代码如下所示

// OnClick functionality works when  running app
class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SampleAppTheme {
                HybridSampleScreen()
            }
        }
    }
}

@Composable
fun HybridSampleScreen() {
    var text by rememberSaveable { mutableStateOf("Initial Text") }
    Surface(
        modifier = Modifier.fillMaxSize(),
        color = MaterialTheme.colors.background
    ) {
        Column() {
            ComposableWithAndroidButton {
                text = "I've been clicked"
            }
            Text(text)
        }
    }
}

@Composable
fun ComposableWithAndroidButton(onButtonClick: () -> Unit) {
    Column() {
        Text(text = "Hello World")
        AndroidView(factory = { context ->
            //This is an alias so I can use Button view and Button Composable in the same file
            ClassicViewButton(context).apply {
                setOnClickListener { onButtonClick.invoke() }
                text = "Click me"
            }
        })
    }
}
Run Code Online (Sandbox Code Playgroud)

测试失败

@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun testAndroidViewButtonInComposable() {
        composeTestRule.setContent {
            SampleAppTheme {
                HybridSampleScreen()
            }
        }

        composeTestRule.onNodeWithText("Hello World").assertIsDisplayed()
        // The first two assertions pass so it looks like Espresso is aware that there is a clickable Button view
        Espresso.onView(ViewMatchers.withText("Click me")).check(matches(isDisplayed()))
        Espresso.onView(ViewMatchers.withText("Click me")).check(matches(isClickable()))
        Espresso.onView(ViewMatchers.withText("Click me")).perform(ViewActions.click())

        composeTestRule.waitForIdle()

        composeTestRule.onNodeWithText("I've been clicked").assertIsDisplayed()
    }
}
Run Code Online (Sandbox Code Playgroud)

为了进行完整性检查,我还创建了一个完全使用可组合项的屏幕,并为其创建了一个测试,并且该测试通过了。

完整撰写屏幕

@Composable
fun FullComposeScreen() {
    var text by rememberSaveable { mutableStateOf("Initial Text") }
    Column {
        ComposableWithComposeButton {
            text = "I've been clicked"
        }
        Text(text = text)
    }
}

@Composable
fun ComposableWithComposeButton(onButtonClick: () -> Unit) {
    Column() {
        Text(text = "Hello World")
        Button(onClick = {
            onButtonClick.invoke()
        }) {
            Text(text = "I'm a composable click me")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

通过测试

@Test
fun testFullComposeButtonInComposable() {
    composeTestRule.setContent {
        SampleAppTheme {
            FullComposeScreen()
        }
    }

    composeTestRule.onNodeWithText("Hello World").assertIsDisplayed()

    composeTestRule.onNodeWithText("I'm a composable click me").assertIsDisplayed()
    composeTestRule.onNodeWithText("I'm a composable click me").assertHasClickAction()
    composeTestRule.onNodeWithText("I'm a composable click me").performClick()

    composeTestRule.waitForIdle()

    composeTestRule.onNodeWithText("I've been clicked").assertIsDisplayed()
}
Run Code Online (Sandbox Code Playgroud)