Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Complete Android UI Testing Landscape: From...

The Complete Android UI Testing Landscape: From Journey to Traditional Approaches

Don't know where to start with Android UI testing? The new AI-powered Journey tests offer a low-code entry point that gets you testing immediately.

In the first part of this talk, we'll explore how to create end-to-end UI tests quickly. We'll cover the fundamentals of effective UI testing and explore how to create effective natural language tests that help you catch bugs before your users do. This might be a perfect launchpad for a developer or team looking to establish a baseline of UI test without a steep learning curve.

However, a single tool rarely fits all needs. In the second half, we will transition from this starting point to a more technical deep-dive. We will put Journey tests head-to-head with another Android UI testing tools, like Espresso, UiAutomator and Compose UI Test framework. Through practical examples, we'll analyze critical aspects, like execution speed, test reliability, flakiness patterns, and long-term maintenance costs at scale.

By the end of this session, you will be able to start your testing journey and know exactly which path to take to improve your app's quality to a high level.

Avatar for Alex Zhukovich

Alex Zhukovich

November 19, 2025
Tweet

More Decks by Alex Zhukovich

Other Decks in Technology

Transcript

  1. Startup/Small company - Focus on shipping fast
 - Manual testing

    done by developers and PMs - Almost no automated UI tests Medium size company - Product is growing
 - More tests, but usually not UI tests Large corporations - Dedicated QA Automation teams
 - Ready to invest in infrastructure How company size influence testing practices alexzh.com
  2. 01. Steep learning curve 02. High maintenance cost 03. Tests

    depend on the state of external devices 04. Missing expertise Why UI testing is complicated? alexzh.com
  3. The Cycle of New Hope New tools and frameworks promise

    easy, fast, and stable tests alexzh.com
  4. Espresso Test Recording The Cycle of New Hope New tools

    and frameworks promise easy, fast, and stable tests alexzh.com
  5. Espresso Test Recording The Cycle of New Hope New tools

    and frameworks promise easy, fast, and stable tests Android Journey alexzh.com
  6. Agenda 02 Deep dive into Android Journey, Maestro, Kaspresso, and

    native frameworks with real examples Ul Testing in Practice 01 Overview of available Android Ul testing options Ul Testing Landscape 03 Compare approaches and find the right tool for your team Framework Comparison alexzh.com
  7. Categories of UI Tests 02 Verify different states of components

    and screens using fake data Ul Tests with fake data 01 Interact with real environment (production server, database, files) End-To-End Tests 03 Verify pixel perfectness of components and screens via screenshots comparison Visual Tests alexzh.com
  8. End-To-End tests Kaspresso Espresso Compose UI Tests Android Journey Maestro

    UI Tests with fake data Compose UI Test Kaspresso Espresso Visual tests Dropshots Paparazzi Roborazzi Shot Android Testify Compose Preview Screenshot Test alexzh.com
  9. 02 Verify different states of components and screens using fake

    data Ul Tests with fake data 01 Interact with real environment (production server, database, files) End-To-End Tests 03 Verify pixel perfectness of components and screens via screenshots comparison Visual Tests alexzh.com
  10. Android Journey Click on "+" button Select “Good" mood Select

    "Reading" and "Meditation" activities Scroll down to the bottom of the screen Add the not "I had a great day" note Click "Save" Verify that “Good" mood is displayed Verify that "Reading" and "Meditation" activities are selected Verify that "I had a great day" note is displayed 1 2 3 4 5 6 7 8 9 alexzh.com
  11. Android Journey <?xml version="1.0" encoding="utf-8"?> <journey name="Add mood and verify

    content on preview"> <description xml:space="preserve">A Journey that ...</description> <actions xml:space="preserve"> <action>Click on "+" button</action> <action>Select "OK" mood</action> <action>Select "Reading" and "Meditation" activities</action> <action>Scroll down to the bottom of the screen</action> <action>Add the not "I had a great day" note</action> <action>Click "Save"</action> <action>Click on the first mood in the list</action> <action>Verify that "OK" mood is displayed</action> <action>Verify that "Reading" and "Meditation" activities are selected</action> <action>Verify that "I had a great day" note is displayed</action> </actions> </journey> alexzh.com
  12. Android Journey tap on the plus fab select the happy

    mood select the Cooking hobby scroll to the bottom of the page add a note: “I made a nice steak” save verify the newly created item has appeared in the list tap on the item verify its details are present 1 2 3 4 5 6 7 8 9 10 Click “+” button Select a “Good” mood, reading and mediation activities, scroll down to add “I had a great day” note and click the save button Open the first note from the list and verify that it has “Good” mood, reading and mediation activities and an “I had a great day” note 1 2 3 Enter a new mood When the mood entry screen opens select mood ok and select for hobbies cooking and relaxation watching movies add a note saying super and save (scroll down if needed) open the newly added mood entry to see the preview verify that the previous action created a new mood entry 1 2 3 4 alexzh.com
  13. Android Journey 02 Gemini analyzes data and decides about next

    action 01 Data send to cloud: action text, screenshot, view tree 03 Journey tool executes action on device alexzh.com
  14. Android Journey Click on "+" button Select "Good" mood Select

    "Reading" and "Meditation" activities Scroll down to the bottom of the screen Add the not "I had a great day" note Click "Save" Click on the first mood in the list Verify that “Good" mood is displayed Verify that "Reading" and "Meditation" activities are selected Verify that "I had a great day" note is displayed Close preview 1 2 3 4 5 6 7 8 9 10 11
  15. Android Journey English language (non-dev friendly) Almost no learning curve

    Single test case can verify UI on multiple device types Every team member can contribute to test creation AI-powered (adaptable but unpredictable) Tests cannot be executed on CI Require Internet for running tests Android Journey bundled with Android Studio alexzh.com
  16. Maestro appId: com.alexzh.moodtracker --- - launchApp # Home screen -

    tapOn: "Add mood" # Add Mood screen - assertVisible: "How do you feel?" - tapOn: "Good" - tapOn: "Writing" - tapOn: "Meditation" - scrollUntilVisible: element: "Add a note" - tapOn: "Add a note" - inputText: "I had a great day" - scrollUntilVisible: element: "Save" - tapOn: "Save" # Home screen - assertVisible: "Add mood" - tapOn: "Good" # Preview screen - assertVisible: "Good" - assertVisible: "Writing" - assertVisible: "Meditation" - assertVisible: "I had a great day" alexzh.com
  17. Maestro Cross-platform tests Single test case can verify UI on

    multiple device types Every team member can contribute to test creation Maestro Studio Require changes for adaptive UI Unreadable tests for complex scenarios Test cases are created in YAML files alexzh.com
  18. Compose UI Test @RunWith(AndroidJUnit4::class) class HomeScreenNavigationTest { @get:Rule val composeTestRule

    = createAndroidComposeRule<MainActivity>() @Test fun addMoodEntry_thenVerifyPreview() { composeTestRule.apply { onNodeWithContentDescription("Add mood") .performClick() onNodeWithText("How do you feel?") .assertIsDisplayed() onNodeWithText("Good") .performClick() onNodeWithText("Writing") .performClick() onNodeWithText("Meditation") .performClick() onNode(hasSetTextAction()) .performScrollTo() .performTextInput("I had a great day") onNodeWithText("Save") .performScrollTo() .performClick()
  19. Compose UI Test @RunWith(AndroidJUnit4::class) class E2ETest { @get:Rule val composeTestRule

    = createAndroidComposeRule<MainActivity>() @Test fun addMoodEntry_thenVerifyPreview() { composeTestRule.apply { homeScreen { addNewMood()} editMoodScreen { createMood( mood = "Good", actions = listOf("Writing", "Meditation"), note = "I had a great day" ) } homeScreen { openPreviewForMoodWithNote("I had a great day") } previewScreen { hasMood( mood = "Good", actions = listOf("Writing", "Meditation"), note = "I had a great day" ) } } } }
  20. Compose UI Test @Before fun setup() { stopKoin() moodRecordDataSource =

    mockk() settingsDataSource = mockk() dateProvider = mockk() startKoin { allowOverride(true) androidContext(...) modules( module { single { moodRecordDataSource } ... } ) } } @After fun tearDown() { stopKoin() } @RunWith(AndroidJUnit4::class) class HomeScreenTest { @get:Rule val composeTestRule = createComposeRule() private lateinit var moodRecordDataSource: MoodRecordDataSource private lateinit var settingsDataSource: SettingsDataSource private lateinit var dateProvider: DateProvider @Test fun homeScreenHasOneItem() { val testDate = LocalDate.of(2025, 1, 15) val mockMoodRecord = MoodRecordWithActions(...) every { dateProvider.getCurrentDate() } returns testDate every { dateProvider.currentDateFlow } returns flowOf(testDate) ... composeTestRule.setContent { HomeScreen(…) } composeTestRule.apply { ... onNodeWithContentDescription("Happy") .assertIsDisplayed() onNodeWithText("Test note for preview") .assertIsDisplayed() } } } alexzh.com
  21. Espresso & Compose UI Test Access to app resources Custom

    DSL improves maintainability Support End-To- End & UI tests with fake data Give maximum control and flexibility Require changes for adaptive UI Developers and QAs only can contribute to test creation Require technical knowledge Support local and instrumentation tests Execution speed alexzh.com
  22. Kaspresso @RunWith(AndroidJUnit4::class) class E2ETest : TestCase() { @get:Rule val composeTestRule

    = createAndroidComposeRule<MainActivity>() @Test fun addMoodEntry_thenVerifyPreview() = run { onComposeScreen<HomeScreen>(composeTestRule) { addMoodFab { performClick() } } onComposeScreen<EditMoodScreen>(composeTestRule) { moodSectionLabel.assertTextEquals("How do you feel?") moodList { child<KNode> { hasContentDescription("Good") } .performClick() } actionList { child<KNode> { hasText("Writing") } .performClick() child<KNode> { hasText("Meditation") } .performClick() } noteInput { performScrollTo() performTextInput("I had a great day") } saveButton { performScrollTo() performClick() }
  23. Kaspresso @RunWith(AndroidJUnit4::class) class E2ETest : TestCase() { @get:Rule val composeTestRule

    = createAndroidComposeRule<MainActivity>() @Test fun addMoodEntry_thenVerifyPreview() = run { onComposeScreen<HomeScreen>(composeTestRule) { addMoodFab { performClick() } } onComposeScreen<EditMoodScreen>(composeTestRule) { moodSectionLabel.assertTextEquals("How do you feel?") moodList { child<KNode> { hasContentDescription("Good") } .performClick() } actionList { child<KNode> { hasText("Writing") } .performClick() child<KNode> { hasText("Meditation") } .performClick() } noteInput { performScrollTo() performTextInput("I had a great day") } saveButton { performScrollTo() performClick() } } onComposeScreen<HomeScreen>(composeTestRule) { addMoodFab { assertIsDisplayed() } moodItemsGrid { child<KNode> { hasContentDescription("Good") } .performClick() } class HomeScreen( semanticsProvider: SemanticsNodeInteractionsProvider ) : ComposeScreen<HomeScreenScreen>( semanticsProvider = semanticsProvider ) { val addMoodFab: KNode = child { hasContentDescription("Add mood") } val moodItemsGrid: KNode = child { hasTestTag("mood_items_grid") } }
  24. Kaspresso @RunWith(AndroidJUnit4::class) class HomeScreenTest : TestCase() { @get:Rule val composeTestRule

    = createComposeRule() private lateinit var moodRecordDataSource: MoodRecordDataSource private lateinit var settingsDataSource: SettingsDataSource private lateinit var dateProvider: DateProvider @Test fun homeScreenHasOneItem() = run { val testDate = LocalDate.of(2025, 1, 15) val mockMoodRecord = MoodRecordWithActions(...) every { dateProvider.getCurrentDate() } returns testDate every { dateProvider.currentDateFlow } returns flowOf(testDate) ... composeTestRule.setContent { HomeScreen(...) } onComposeScreen<HomeScreenScreen>(composeTestRule) { addMoodFab { assertIsDisplayed() } moodItemsGrid { ... child<KNode> { hasContentDescription("Good") } .assertIsDisplayed() child<KNode> { hasText("Test note for preview") } .assertIsDisplayed() } } } } @Before fun setup() { stopKoin() moodRecordDataSource = mockk() settingsDataSource = mockk() dateProvider = mockk() startKoin { allowOverride(true) androidContext(...) modules( module { single { moodRecordDataSource } ... } ) } } @After fun tearDown() { stopKoin() } alexzh.com
  25. Kaspresso Access to app resources Readable test cases Support End-To-

    End & UI tests with fake data Flaky test handling Require changes for adaptive UI Developers and QAs only can contribute to test creation Require technical knowledge Support local and instrumentation tests Execution speed Improved test reports alexzh.com
  26. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Adaptive UI support Test maintenance Execution speed How tests are written Who can create tests Cost alexzh.com
  27. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Adaptive UI support Test maintenance Execution speed How tests are written English language XML files Who can create tests Cost Maestro syntax YAML files Framework syntax Kotlin/Java files alexzh.com
  28. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Adaptive UI support Test maintenance Execution speed How tests are written English language XML files Who can create tests Everyone Cost Maestro syntax YAML files Everyone Framework syntax Kotlin/Java files Developers & QAs alexzh.com
  29. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Low control Adaptive UI support Test maintenance Execution speed How tests are written English language XML files Who can create tests Everyone Cost Low control Maestro syntax YAML files Everyone High control Framework syntax Kotlin/Java files Developers & QAs alexzh.com
  30. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Low control Adaptive UI support No additional work needed Test maintenance Execution speed How tests are written English language XML files Who can create tests Everyone Cost Low control Require additional work Maestro syntax YAML files Everyone High control Require additional work Framework syntax Kotlin/Java files Developers & QAs alexzh.com
  31. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Low control Adaptive UI support No additional work needed Test maintenance Low maintenance Execution speed How tests are written English language XML files Who can create tests Everyone Cost Low control Require additional work Medium maintenance Maestro syntax YAML files Everyone High control Require additional work High maintenance if no DSL Framework syntax Kotlin/Java files Developers & QAs alexzh.com
  32. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Low control Adaptive UI support No additional work needed Test maintenance Low maintenance Execution speed Slow
 Test scenario: 72s How tests are written English language XML files Who can create tests Everyone Cost Low control Require additional work Medium maintenance Medium
 Test scenario: 22s Maestro syntax YAML files Everyone High control Require additional work High maintenance if no DSL Fast
 Test scenario: 1.5s Framework syntax Kotlin/Java files Developers & QAs alexzh.com
  33. Android Journey Maestro Espresso , Compose UI Test, Kaspresso Data

    & state control Low control Adaptive UI support No additional work needed Test maintenance Low maintenance Execution speed Slow
 Test scenario: 72s How tests are written English language XML files Who can create tests Everyone Cost Free*
 (as currently in beta) Low control Require additional work Medium maintenance Medium
 Test scenario: 22s Maestro syntax YAML files Everyone Free*
 (has optional paid service) High control Require additional work High maintenance if no DSL Fast
 Test scenario: 1.5s Framework syntax Kotlin/Java files Developers & QAs Free alexzh.com
  34. 02 Verify different states of components and screens using fake

    data Ul Tests with fake data 01 Interact with real environment (production server, database, files) End-To-End Tests 03 Verify pixel perfectness of components and screens via screenshots comparison Visual Tests alexzh.com