Compose UI Testing: Find Nodes, Assert State, Perform Actions

Compose UI tests treat your UI as a node tree. You find nodes by properties (like text or a test tag), assert their state (e.g., 'is displayed'), and perform actions like clicks. Use it to verify composables react correctly to state changes or user input.
WHY IT EXISTS: Declarative UI frameworks like Compose rebuild the UI from state, so traditional view-based testing (findViewById) is obsolete. Compose testing provides a new API to interact with the UI tree based on its semantic properties, not its underlying implementation.
THE MENTAL MODEL: Think of your UI not as a hierarchy of views, but as a data structure—a "semantics tree". Your test is a program that queries this tree. You don't care about implementation details like Column or Row; you care about what the user perceives: nodes with text, clickable buttons, or images with content descriptions.
HOW IT WORKS: You use a ComposeTestRule, typically from createComposeRule(), to host your composable under test. Inside a test function, you call setContent to render your UI. Then, you use finders like onNodeWithText("Save") or onNodeWithTag("submit_button") to get a handle on a UI element. Finally, you chain assertions (assertIsDisplayed()) and actions (performClick()) on that handle. The test runner automatically synchronizes these operations with the Compose frame clock, waiting for the UI to settle.
WHEN TO USE IT: Use it for screen-level tests to verify the integration of multiple composables, or for component-level tests to check a single, isolated composable's behavior. It's perfect for checking that UI state changes are correctly reflected in the rendered output, like showing a progress indicator when an isLoading state becomes true.
WHEN NOT TO USE IT: Do not use UI tests for pure business logic. If a ViewModel contains complex calculations, test the ViewModel directly in a fast, simple unit test. UI tests are slower and more resource-intensive. Also, avoid testing the behavior of standard library composables (e.g., does a Material Button actually click?). Trust the framework; test your application code.
ONE CANONICAL EXAMPLE: To test a login screen, a test would first find the username and password fields using onNodeWithTag. It would use performTextInput to enter credentials. Then, it would find the login button, perhaps with onNodeWithText("Login"), and call performClick. Finally, it would assert that a progress bar is now visible with onNodeWithTag("loading_spinner").assertIsDisplayed() and that the login button is disabled.
Read the original → developer.android.com
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.