What is Espresso Testing? A Comprehensive Tutorial for Android Developers
Have you ever faced quality issues that slipped through the cracks into production? As an Android developer, learning test automation using Espresso can help prevent such issues.
With over 70% of Android developers now using Espresso for test automation, it has emerged as the top choice for Android UI testing. This comprehensive tutorial explains what Espresso is, how it works under the hood, steps to write and run reliable Espresso tests, integration with emulators/real devices and expert best practices.
What Exactly is Espresso Testing?
Espresso is an open-source automation testing framework developed by Google that makes writing reliable Android UI tests easy.
Let‘s break down what Espresso testing means:
- Automation Testing: Tests that run automatically without manual intervention
- UI Testing: Validate look, feel and behaviour of user interfaces
- Android: Used for testing Android mobile apps
The main value Espresso provides is automatically synchronizing test actions with the app UI, so you don‘t have to add delays and sleeps within tests. This leads to reliable tests that run fast without any timing issues.
Espresso tests consist of 3 key steps:
- Finding views to interact using ViewMatchers
- Performing actions like click, scroll, input text using ViewActions
- Validating outcomes using ViewAssertions
Here is an example test for email validation:
// Enter invalid email
onView(withId(R.id.email)).perform(typeText("john#gmail.com"))
// Verify error message displayed
onView(withText("Invalid email format")).check(matches(isDisplayed()))
Espresso handles test synchronization, failure screenshots and detailed reports – providing a robust framework for test automation engineers with minimal effort.
Having worked on Espresso testing for various mobile apps over the last 10+ years, I‘ll share my insider tips to help you become productive quickly. This tutorial covers:
- How Does Espresso Synchronize Tests
- Setting Up Espresso
- Writing Reliable Tests
- Executing Test Suites
- Debugging Issues
- Integration with Devices
- Espresso Best Practices
So let‘s get started with understanding how Espresso works under the hood!
How Does Espresso Synchronize Tests?
The key value Espresso brings is automatic synchronization between test steps and UI events. But how does this work exactly?
Espresso leverages the message queue based mechanism that Android uses for UI updates and event handling.
When you perform a test action like entering text or clicking a button, Espresso adds it to the message queue. The application‘s main thread processes events from this queue and updates the UI.
Once queue processing is complete, Espresso then asserts outcomes or performs next actions within default 5 seconds timeout. This keeps test steps in sync with UI responsive periods inherently.
Espresso also provides Idling Resources to integrate with background tasks like network calls, database operations etc. This makes tests wait until specific jobs complete before continuing – minimizing flakiness.
You get out-of-the-box synchronization without having to explicitly code waits, sleeps or set fixed timeouts!
Let‘s look at settings needed to configure Espresso next.
Setting Up Espresso
The good news is Espresso directly integrates with Android Studio and standard JUnit workflow requiring minimal setup.
Here are key steps:
1. Configure Test Environment
Start by turning animations OFF on test devices or emulators:
adb shell settings put global window_animation_scale 0
adb shell settings put global transition_animation_scale 0
adb shell settings put global animator_duration_scale 0
This prevents possible race conditions with animations interfering with tests.
2. Add Gradle Dependencies
Include the following in app/build.gradle:
androidTestImplementation ‘androidx.test.espresso:espresso-core:3.4.0’
androidTestImplementation ‘androidx.test:runner:1.4.0’
androidTestImplementation ‘androidx.test:rules:1.4.0’
Make sure to sync project after this.
3. Specify Instrumentation Runner
In the same build.gradle file, add:
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
This configures Espresso test runner when executing tests.
That‘s it! Espresso is now ready to start writing UI tests.
Writing Reliable Espresso Tests
The core philosophy around test automation is having reliable tests that catch issues early without false failures.
Let‘s explore Espresso test anatomy with examples:
1. Find Views
Use ViewMatchers to locate UI elements, for example:
onView(withId(R.id.fullname_textview))
onView(withText("Submit"))
You can match views using resourceId, text, content description etc.
2. Perform Actions
ViewActions define user interactions like click, input text, swipe screen:
perform(click())
perform(typeText("Hello World"))
perform(swipeLeft())
Complex chains can be built using custom ViewActions.
3. Assert Outcomes
ViewAssertions validate state of views after actions:
check(matches(isDisplayed()))
check(matches(withHint("Email")))
Standard assertThat(view, matcher) can also be used for custom cases.
This example logs into an app:
// Enter credentials
onView(withId(R.id.username)).perform(typeText("john_doe"))
onView(withId(R.id.password)).perform(typeText("paS$1234"))
// Click Sign In
onView(withText("Sign In")).perform(click())
// Verify home screen displays
onView(withText("Home")).check(matches(isDisplayed()))
Let‘s look at some best practices next.
Espresso Test Best Practices
Here are some key points to ensure maintainable and reliable test automation:
1. Ensure Isolation
Tests should not depend on or impact other tests – important for parallel runs. Start each test from a clean state.
2. Parameterize Input Data
Pass values like login credentials, file contents via @Parameters annotation to make tests data driven.
3. Adopt Page Object Pattern
Create reusable page objects to represent screens that encapsulate UI locators and business logic.
4. Analyze Root Causes
Dig deeper during test failure analysis to find root causes vs. quick fixes. Capture enough evidence.
5. Set Realistic Timeouts
Use IdlingResources instead of Sleeps with optimal timeout periods based on app needs.
6. Prevent Test Flakiness
Identify flaky tests upfront in CI pipelines using reruns, quarantine unstable tests impacting overall reliability.
This requires some diligence but pays of in long term owning a stable automated test suite!
Executing Espresso Test Suites
Espresso tests can be executed directly within Android Studio or command line:
Run Within Android Studio
- Go to Run > Edit Configurations
- Add a new Android Tests configuration
- Select app module
- Connect physical device or start emulator
- Execute tests!
Command Line Execution
Use below command to run connected tests:
./gradlew connectedAndroidTest
You can also trigger test runs through CI/CD pipelines like Jenkins, CircleCI etc. Leverage BrowserStack‘s Espresso integration for cloud-based executions.
Debugging Espresso Test Failures
Here are some best practices around debugging failures:
- Detailed Logs: Turn on debug logs using
adb shell setprop log.tag.Espresso DEBUG - Screenshots: Espresso automatically captures screenshot for every failed step
- Videos: Being able record test run helps identify race conditions
- Dependency Analysis: Analyze external dependencies causing flakiness (API failures etc)
- Reruns: Flaky tests can be automatically rerun until pass or identify as unstable
- Test Reports: Aggregate reports provide insights into failure trends
Getting to root causes upfront saves ample debugging time in long run!
Integrating Devices and Emulators
While emulators allow quick testing, real devices help validate real world scenarios accurately:
Emulators
Create Android Virtual Devices (AVD) across different OS versions, screen sizes etc. Turn animations OFF with adequate RAM for stability.
Real Devices
Cloud device labs like BrowserStack and Firebase Test Lab provide access to hundreds of real android and iOS devices to run tests identically across multiple target devices.
This allows testing:
- Different Android versions – Pie, Oreo, Nougat etc.
- Varied screen sizes – 720p, 1080p, 2K
- Range of hardware capabilities
- Real world network conditions
- App performance metrics
Provide your team access to real devices without procuring and maintaining in-house labs.
Espresso Testing Best Practices
Let‘s conclude with a checklist of key best practices:
🔹 Turn off animations on test devices
🔹 Ensure isolation between test cases
🔹 Parameterize tests with external data
🔹 Adopt Page Object pattern for maintainability
🔹 Set Idling Resources to integrate with background tasks
🔹 Analyze root causes behind test failures
🔹 Mitigate test flakiness in CI pipeline
🔹 Compare on both emulators and real devices
🔹 Track test metrics and monitor over time
Getting your Espresso test automation project right requires some vigilance upfront but pays off greatly improving product quality and developer productivity in the long term!
So go ahead, leverage these best practices to setup reliable automated checks for your Android app UI. Feel free to reach out in comments below if facing any challenges.
Happy test automation!