如何将 Robolectric 和 AndroidX 与 Jetpack Compose 结合起来构建单元测试?

Ali*_*lix 8 robolectric kotlin androidx-test android-jetpack-compose

假设

  • Robolectric 控制要模拟哪个 Android 版本,所以我需要这个
  • AndroidX 有 Jetpack Compose 的测试 API,所以我也需要这个

背景

在运行完整的测试套件时,我经历了很多AppNotIdleException,但大多数情况下它们都是单独成功运行的(相关: https: //github.com/robolectric/robolectric/issues/7055)。我想确切地了解这两个 API 应如何组合以避免出现问题。

对于初学者来说,Robolectric 中有一个称为“Looper 模式”的配置,它基本上定义了何时执行不同的线程。从 Robolectric 4.5 开始,默认值是“PAUSED”,这意味着开发人员应该控制线程的执行时间。

此外,AndroidX 提供了createComposeRule(),这使得使用单个可组合项构建最小的单元测试成为可能 - 非常好。 此“撰写规则”附带一个“mainClock”,其默认行为为“自动前进”

问题

给出一个带有按钮的简单可组合项。我的测试的推荐设置(注释、时钟配置等)是什么?假设我希望测试针对 Android P (API=28) 运行。欢迎任何反馈。我想尽可能保持测试整洁。

代码

这就是我今天编写测试的方式:

@Config(sdk = [Build.VERSION_CODES.P])
@RunWith(AndroidJUnit4::class)
@LooperMode(LooperMode.Mode.PAUSED)
class MyComposablesKtTest {

    @get:Rule
    val composeTestRule = createComposeRule()

    private val buttonNode get() = composeTestRule.onNodeWithContentDescription("My Button")

    @Before
    fun setUp() {
        composeTestRule.mainClock.autoAdvance = false
    }

    @Test
    fun `MyComposable - always - sets up view correctly`() {
        composeTestRule.setContent {
            MyComposable(onClick = {})
        }
        composeTestRule.mainClock.advanceTimeByFrame()

        buttonNode.assertExists().assertHasClickAction().assertIsEnabled()
    }

    @Test
    fun `MyComposable - when button clicked - performs action`() {
        var buttonClicked = false
        composeTestRule.setContent {
            MyComposable(onClick = { buttonClicked = true })
        }
        composeTestRule.mainClock.advanceTimeByFrame()

        buttonNode.performClick()

        assertTrue(buttonClicked)
    }

}

Run Code Online (Sandbox Code Playgroud)