Possible to set up Android Compose UI testing without passing the composeTestRule around?

36 views Asked by At

I want to be able to wrap compose test code so my tests are easier to write and look cleaner. Unfortunately, and as far as I can tell, compose testing needs the composeTestRule variable to find elements and assert on them. The below code works:

@Rule
@JvmField
val composeTestRule: ComposeContentTestRule = createAndroidComposeRule<ComposeActivity>()

// Note: I'm not using both composeTestRule vars here, either works and I don't see the difference in calling the activity or not.
// Separate question, but in case anyone feels like answering it here, what's the point of the top one?

@get:Rule
val composeTestRule = createComposeRule()

@Test
fun testComposeScreenDisplaysText() {
    renderComposeScreen(ComposeScreen())
    shouldSeeText(composeTestRule, "Hello Android!")
    shouldSeeText(composeTestRule, "Filler text")
    shouldSeeText(composeTestRule, "This is a simple test")
}

The shouldSeeText function looks like:

fun shouldSeeText(composeTestRule: ComposeTestRule, text: String) {
    composeTestRule.onNodeWithText(text).assertIsDisplayed()
}

This is not what I want as it is noisy and cumbersome to pass the composeTestRule to every single function in my tests. This is what I would like to be able to do:

@Test
fun testComposeScreenDisplaysText() {
    renderComposeScreen(ComposeScreen())
    shouldSeeText("Hello Android!")
}

I have not been able to make this work though. How can I make it so I can run tests that navigate through multiple activities in my app, but not have to pass the composeTestRule var into each function?

1

There are 1 answers

1
BenjyTec On

I think it is not a good approach to pass around a ComposeTestRule. Tests should be as isolated and independent from each other as possible. If you pass a ComposeTestRule to different classes,

  1. it is not wuite clear which preconditions are expected before executing a test function,
  2. the tests in different classes strongly depend on each other and
  3. if one test fails, the subsequent tests in other classes are going to fail, too.
  4. You then will have a hard time figuring out which test was the one that failed first.

I would encourage you to better use only one ComposeTestRule per test class.

However to make shouldSeeText function available in all test classes, you can make use of extension functions.

Create a Kotlin file like TestExtensions.kt in your androidTest package. In this file, place the following code:

fun ComposeTestRule.shouldSeeText(
    text: String
) {
    onNodeWithText(text).assertIsDisplayed()
}

Now, you can simply call

composeTestRule.shouldSeeText("Hello")

in each of your test classes.