Android E2E Automaton Test with UI Automator 🤖

Photo by ZMorph Multitool 3D Printer on Unsplash

Like what you see? This is achieved with the help of UI Automator. A powerful testing framework that provides APIs to simulate application wide and platform wide operations. The most used two in my opinion are:

  1. BySelector/UiSelector: Represents a query for one or more target UI elements on a device.
  2. UiObject: Represents a UI element that is visible on the device.

Suppose in our app, we have a page with a list of blog posts which we can navigate to by clicking on the hamburger menu then clicking on the Posts text. On the page we have a carousel widget that auto plays our posts by default. We can click on the cover image and navigate to a post detail page. And when clicking back button, we should be brought back to the blog posts page. Now we want to set up a test for this set of interactions. This is a simple yet perfect use case for UI Automator.

Add dependency

dependencies {
androidTestImplementation'androidx.test.uiautomator:uiautomator:2.2.0'
}

Set up UI Automator

private lateinit var device: UiDevice

@Before
fun init() {
// Initialize UiDevice instance
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

// Find and open hamburger menu
device.findObject(By.desc("Open navigation drawer")).click()

// Find and navigate to Posts page
onView(allOf(withResourceName("menu_item"),withText("Posts"))).perform(click())
}

Test

/**
* Carousel component should navigate to and back from post detail page
*/
@Test
fun carouselNavigatesToAndBackFromDetailPage() {
// Make sure carousel navigates to post detail page upon click
onView(withId(R.id.carouselPostCoverImage)).perform(click())
// Blog posts are not visible
onView(withId(R.id.postsFragmentLayout)).check(doesNotExist())
// Detail fragment layout should be visible
onView(withId(R.id.detailFragmentLayout)).check(matches(isDisplayed()))

pressBack()

// Blog posts are displayed
onView(withId(R.id.postsFragmentLayout)).check(matches(isDisplayed()))
// Detail fragment is not visible
onView(withId(R.id.detailFragmentLayout)).check(doesNotExist())
}

Complete code

/**
* E2E test for BlogPosts page
*/
@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 18)
class BlogPostsTest {
/**
* Clear app local storage
*/
@get:Rule
val clearLocalStorageRule = ClearLocalStorageRule(MainActivity::class.java)

/**
* Handle async actions
*/
@get:Rule
val idlingResourceRule = IdlingResourceRule()

private lateinit var device: UiDevice

@Before
fun init() {
// Initialize UiDevice instance
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())

// Find and open hamburger menu
device.findObject(By.desc("Open navigation drawer")).click()

// Find and navigate to Posts page
onView(allOf(withResourceName("menu_item"),withText("Posts"))).perform(click())
}

/**
* Carousel component should navigate to and back from post detail page
*/
@Test
fun carouselNavigatesToAndBackFromDetailPage() {
// Make sure carousel navigates to post detail page upon click
onView(withId(R.id.carouselPostCoverImage)).perform(click())
// Blog posts are not visible
onView(withId(R.id.postsFragmentLayout)).check(doesNotExist())
// Detail fragment layout should be visible
onView(withId(R.id.detailFragmentLayout)).check(matches(isDisplayed()))

pressBack()

// Blog posts are displayed
onView(withId(R.id.postsFragmentLayout)).check(matches(isDisplayed()))
// Detail fragment is not visible
onView(withId(R.id.detailFragmentLayout)).check(doesNotExist())
}
}

As you can see I have used two custom test rules which you can ignore for now. I will talk more about custom test rules in a future post. As a general rule of thumb, UI/automation tests can grow relatively large in size which increases fidelity but also increases execution time and effort to maintain and debug. Therefore, we should keep the amount of these tests small.

Example of test pyramid

Hope you have an idea about UI Automator and can start writing a simple E2E test now. If you have enjoyed this article please give it a clap, I will see you in the future posts.

Keep calm and code on!

--

--

--

Software Developer | Tech Junkie | Professional Nap Taker 🐨

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Animating RecyclerView items

Google Maps & Google places with Android Studio (Part 1 - How setup API key)

Tips & Tricks to Build a Successful Mobile App

Guiding user input on EditText

Flutter- sending data between android and flutter

Navigation on Android — past, present and future

Android RecyclerView With Kotlin Sealed Classes

Phone placed vertically

How To Monitor Internet Connection in Android Using Kotlin and LiveData

person using the touchpad on a notebook computer

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Brian Wang

Brian Wang

Software Developer | Tech Junkie | Professional Nap Taker 🐨

More from Medium

Integration of Huawei Crash Service in Quiz Android app (Kotlin) — Part 5

Only the Original Thread that Created a View Hierarchy can Touch its Views

Notification Alert! Integration of Huawei Push Kit in Application (Kotlin)

TDD — Part III, Hilt and Robolectric (Android)