Mercari QA and Compose for Android automation

Written by Lester Xie (special thanks to Martin Arellano)

OVERVIEW & PURPOSE

Testing is an essential part of the development process, and Android test automation has evolved over the years. In keeping with the latest trends, Mercari engineering always looks for opportunities to improve. In this article, I will discuss the Compose Framework for automating UI tests and the advantages and some examples of how we use it at Mercari. Previously, our UI tests were written using the Espresso framework. While Espresso is a powerful tool for testing Android UI, it can be quite verbose and difficult to read. Compose, on the other hand, uses a declarative syntax that is more intuitive and easier to read. This means that you can write tests more quickly and with less code.

  • Compose offers a more intuitive way to write UI tests
    Compose’s declarative syntax is more intuitive and easier to read than Espresso’s imperative syntax. Compose allows you to create UI components as functions that take in input parameters and return a UI tree. This makes it easy to test individual UI components in isolation, without needing to navigate through the entire app. With Compose, you can write tests more quickly and with less code, which leads to faster development and more efficient testing.
  • Compose allows you to test your UI components in isolation
    One of the challenges of testing Android UI is that it can be difficult to isolate individual UI components for testing. With Compose, you can create UI components as functions that take in input parameters and return a UI tree. This makes it easy to test individual UI components in isolation, without needing to navigate through the entire app. By testing UI components in isolation, you can catch issues early in the development process and save time and effort in debugging.
  • Compose offers a more reliable way to test UI changes
    One of the common issues with UI testing is that it can be difficult to test UI changes reliably. With Compose, you can use the assert() function to check that your UI components are rendering as expected. This allows you to test UI changes more reliably and catch issues early in the development process. By catching UI issues early, you can reduce the risk of introducing bugs and improve the overall quality of your app.
  • Compose is faster to execute than traditional UI tests
    Another advantage of using Compose for Android test automation is that it is faster to execute than traditional UI tests. This is because Compose UI components are compiled into a tree structure, which can be cached and reused across multiple tests. This means that your tests will run faster and with less overhead. By using Compose, you can save time and effort in testing and improve the overall efficiency of your development process.
  • Compose offers better support for testability
    Finally, Compose offers better support for testability than traditional Android UI frameworks. This is because Compose components are designed to be more modular and testable. You can use tools like MockK to create mock objects for your Compose components, which makes it easier to test them in isolation. By making your UI components more modular and testable, you can improve the overall quality of your app and reduce the risk of introducing bugs.

In this article, I will show some best practices we use at Mercari to showcase ease of use and simplicity.

Example 1

fun goToMyPage() = MyPage.apply {
    composeTestRule.onNodeWithText(R.string.bottom_nav_title_my_page)
        .performClick()
}

R.string.bottom_nav_title_my_page is a string resource for localization defined in strings.xml

<string name="bottom_nav_title_my_page">My Page</string>

This one taps My Page on the bottom menu tab and returns MyPage object.
Where there is a text available on the screen, we can use the text to tap or assert the string.
You can write in this form most of the times:

Example 2

fun tapBack() = TopPage.apply{
    composeTestRule.onAllNodersWithTag("go back")[0]
        .onChildren()[0]
        .onChildAt(0)
        .performClick()
}

This is to click an arrow on the left to go back from item detail page.

Since that has no text, I had to do in the other way to press the arrow button.
In Compose, we can use Semantics which tags a value to use for testing.
Semantics = “the meaning of"; in this case, it gives a meaning to a piece of UI.
I have tagged the arrow as in following:

ItemDetailScreen.kt

topBar = {
    TopNavigation(
        title = stringResource(id = R.string.title_itemDetailFragment),
        navigationIcon = DsIcons.arrowback,
        onNavigationClick = onUpPress,
        modifier = Modifier.testTag("go back")
    )
},

So far, I use 2 ways to tag a value.

  1. Use Modifier
    modifier = Modifier.testTag("go back") is something I added so I get the means to click the arrow.
  2. Use contentDescription
    Thumbnail(
    data = item.thumbnails.firstOrNull(),
    contentDescription = THUBNAIL_CONTENT_DESCRIPTION,
    fadeIn = fadeIn,
    )

    SearchResultScreen.kt
    If there is a contentDescription filled, you could use that too.
    To specify the target node among all the nodes, define a condition to filter and find the specific node in the tree.

Also, we can use onChildren().onFirst which also gets the first node.
To see the tree node, use composeTestRule.onRoot().printToLog("TAG") which prints the node structure.

Here you can see go back tag and structure-wise, it shows up like this:

This is very readable and allows us to view elements in the tree.
We can tell the node that has Button and OnClick Action is the back arrow.
Just find how you can locate the position relative to other nodes.

You can also view the hierarchy during the test execution by setting a breakpoint and typing the printLog statement in evaluation window.

Example 3

composeTestRule.onNode(
    hasText(R.string.email_login_button) and
        hasClickAction(),
).performClick()

You can also use this style to find a specific node. The above one is telling to click on a node that has a string identified by email_login_button and it also has ClickAction.

Conclusion

In the Mercari QA team, we found this framework smooth as it is native with Android development. As you can see from our examples our code is very readable and easily maintainable. Our developers can read our test code as it is in the same language and technology stack they are using. We are currently utilizing Compose in our release sanity check and running weekly to look for any regressions in our application. I hope you found this article useful and happy hunting. =)

  • X
  • Facebook
  • linkedin
  • このエントリーをはてなブックマークに追加