测试错误:MyActivity已经设置内容。如果您已使用 ComposeView 填充 Activity,请确保在该 ComposeView 上调用 setContent

问题描述 投票:0回答:4

使用最新版本的 Compose 1.2.0 运行 Robolectric 单元测试时,使用

createAndroidComposeRule
的测试会失败并出现以下错误:

MyActivity 已设置内容。如果您已使用 ComposeView 填充 Activity,请确保在该 ComposeView 上调用 setContent,而不是在测试规则上调用;并确保在 ComposeTestRule 运行后完成对

setContent {}
的调用

来自失败测试之一的代码:

composeTestRule.setContent {
    Column {
        Text(textTitle)
        DemoScopedInjectedViewModelComposable()
    }
}
android android-jetpack-compose android-testing
4个回答
40
投票

仔细观察,错误消息很有帮助,即使它谈论的是

ComposeView
而不是
Activity
。但根据它:

composeTestRule.setContent { ... }

应改为:

composeTestRule.activity.setContent { ... }

并且测试应该运行而不会再出现此错误。

或者,确保您的活动正在扩展

ComponentActivity
,因此
composeTestRule.setContent { ... }
应该可以正常工作。


7
投票

Compose 1.2 具有 forbidden 来覆盖活动规则的内容。但这仍然可以通过直接在 Activity 上设置内容来完成,而不是 Activity 测试规则。

解决此问题的最简单方法是不在活动规则上设置内容,而是在活动本身上设置内容。可以这样做:

composeTestRule.activity.runOnUiThread {
    composeTestRule.activity.setContent {
        Column {
            Text(textTitle)
        }
    }
}

为了简化使用,您可以使用以下扩展

fun <R : TestRule, A : ComponentActivity> AndroidComposeTestRule<R, A>.setContentOnActivity(
    content: @Composable () -> Unit
) {
    this.activity.runOnUiThread {
        this.activity.setContent {
            content()
        }
    }
}

1
投票

解决方案是从 Activity 中获取 Compose View(该 Activity 在测试规则中可用),然后在该 View 上调用

setContent
,而不是直接在测试规则上调用,如错误消息所示。

这是我创建的一个测试辅助函数,以避免在测试中出现此问题:

fun AndroidComposeTestRule<ActivityScenarioRule<MyActivity>, MyActivity>.clearAndSetContent(content: @Composable () -> Unit) {
    (this.activity.findViewById<ViewGroup>(android.R.id.content)?.getChildAt(0) as? ComposeView)?.setContent(content)
        ?: this.setContent(content)
}

更新测试:

composeTestRule.clearAndSetContent {
    Column {
        Text(textTitle)
        DemoScopedInjectedViewModelComposable()
    }
}

作为参考,这是我的测试规则:

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

1
投票

在设置

ComponentActivity
时使用
MainActivity
代替
composeTestRule
对我有用:

class MainActivityInstrumentedTest {

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

}
© www.soinside.com 2019 - 2024. All rights reserved.