To delve into Android app automation using UiAutomator, here are the detailed steps to get started quickly and efficiently:
👉 Skip the hassle and get the ready to use 100% working script (Link in the comments section of the YouTube Video) (Latest test 31/05/2025)
Check more on: How to Bypass Cloudflare Turnstile & Cloudflare WAF – Reddit, How to Bypass Cloudflare Turnstile, Cloudflare WAF & reCAPTCHA v3 – Medium, How to Bypass Cloudflare Turnstile, WAF & reCAPTCHA v3 – LinkedIn Article
-
Setting up Your Environment:
- Install Java Development Kit JDK: UiAutomator tests are written in Java. Download and install the latest JDK from Oracle’s official site: https://www.oracle.com/java/technologies/downloads/
- Install Android Studio: This IDE is essential for Android development and includes the Android SDK, which contains the UiAutomator tools. Download it from: https://developer.android.com/studio
- Configure Android SDK: Ensure your
ANDROID_HOME
environment variable points to your SDK location typicallyC:\Users\YourUser\AppData\Local\Android\Sdk
on Windows or~/Library/Android/sdk
on macOS. Add theplatform-tools
andtools
directories to yourPATH
. - Set up a Device/Emulator: You’ll need an Android device connected via USB with Developer options and USB debugging enabled, or an AVD Android Virtual Device configured in Android Studio.
-
Understanding UiAutomator Viewer:
- This critical tool allows you to inspect the UI components of an Android application.
- Open it by navigating to
your_sdk_path/tools/bin
and runninguiautomatorviewer.bat
Windows oruiautomatorviewer
macOS/Linux. - Connect your device/emulator, open the app you want to automate, and click the “Device Screenshot” button in UiAutomator Viewer to capture a snapshot of the current screen.
- The viewer will display the UI hierarchy, showing properties like
resource-id
,text
,content-desc
, andclass
which are crucial for identifying elements in your automation script.
-
Creating Your First UiAutomator Project:
-
In Android Studio, create a new project. You can start with an “Empty Activity” template, though for UiAutomator, the activity itself isn’t the focus.
-
Add UiAutomator Dependencies: Open your
app/build.gradle
file and add the following dependencies within thedependencies
block, typically underandroidTestImplementation
:androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' androidTestImplementation 'androidx.test:runner:1.4.0' androidTestImplementation 'androidx.test:rules:1.4.0'
Always check for the latest versions on the official AndroidX documentation.
-
Create a Test Class: In the
androidTest
directory e.g.,app/src/androidTest/java/com/example/yourapp
, create a new Java class, for example,ExampleUiAutomatorTest.java
.
-
-
Writing Your First Test Script Example:
- Inside your test class, you’ll use
UiDevice
to interact with the device andUiObject
/UiSelector
to find and manipulate UI elements.
package com.example.yourapp. // Adjust package name import androidx.test.ext.junit.runners.AndroidJUnit4. import androidx.test.platform.app.InstrumentationRegistry. import androidx.test.uiautomator.By. import androidx.test.uiautomator.UiDevice. import androidx.test.uiautomator.UiObject. import androidx.test.uiautomator.UiObject2. import androidx.test.uiautomator.UiSelector. import androidx.test.uiautomator.Until. import org.junit.Before. import org.junit.Test. import org.junit.runner.RunWith. import static org.junit.Assert.assertNotNull. import static org.junit.Assert.assertTrue. @RunWithAndroidJUnit4.class public class ExampleUiAutomatorTest { private UiDevice device. private static final String PACKAGE_NAME = "com.android.settings". // Example: Android Settings app @Before public void setup { // Initialize UiDevice device = UiDevice.getInstanceInstrumentationRegistry.getInstrumentation. assertNotNulldevice. // Ensure device is initialized // Press home button to start from a known state device.pressHome. // Launch the target app device.waitUntil.hasObjectBy.pkgPACKAGE_NAME.depth0, 5000. device.executeShellCommand"am start -n " + PACKAGE_NAME + "/.Settings". // Adjust component if needed } @Test public void testOpenWiFiSettings throws Exception { // Wait for Settings app to open device.waitUntil.hasObjectBy.text"Settings", 5000. // Find and click on "Network & internet" or similar UiObject networkOption = device.findObjectnew UiSelector.text"Network & internet". if networkOption.exists && networkOption.isClickable { networkOption.click. } else { // Fallback for different text or older Android versions networkOption = device.findObjectnew UiSelector.textContains"Network". if networkOption.exists && networkOption.isClickable { networkOption.click. } } device.waitUntil.hasObjectBy.text"Internet", 5000. // Wait for next screen // Find and click on "Internet" or "Wi-Fi" UiObject wifiOption = device.findObjectnew UiSelector.text"Internet". if wifiOption.exists && wifiOption.isClickable { wifiOption.click. wifiOption = device.findObjectnew UiSelector.text"Wi-Fi". // Older versions if wifiOption.exists && wifiOption.isClickable { wifiOption.click. // Assert that the Wi-Fi switch or list is visible assertTrue"Wi-Fi screen not visible", device.waitUntil.hasObjectBy.text"Wi-Fi", 5000 || device.waitUntil.hasObjectBy.desc"Wi-Fi switch", 5000 . }
- Inside your test class, you’ll use
-
Running Your Tests:
- Connect your Android device or start an AVD.
- In Android Studio, open your test class. You’ll see a green play icon next to the class name or individual test methods. Click it and select “Run ‘ExampleUiAutomatorTest’”.
- Android Studio will build and install the test APK on your device/emulator, and then execute the automation script. Observe the device as the test runs.
This straightforward process outlines the core steps.
Remember to use UiAutomatorViewer
frequently to identify the correct selectors for your target app’s UI elements, as IDs and text can vary across Android versions and app implementations.
Deep Dive into Android App Automation with UiAutomator
Android app automation has become an indispensable tool for quality assurance, enabling developers and testers to ensure the robustness and reliability of their applications.
Among the myriad of testing frameworks available, UiAutomator stands out as a powerful and practical solution, particularly for cross-app functional UI testing.
Developed by Google, UiAutomator is an Android testing framework that allows you to simulate user interactions on physical devices and emulators, directly interacting with UI elements at a system level.
This makes it ideal for black-box testing, where you don’t necessarily have access to the app’s internal code, focusing instead on its user interface and behavior.
According to a report by Statista, global mobile app downloads exceeded 257 billion in 2023, underscoring the massive scale and critical need for efficient app testing. Circleci vs gitlab
UiAutomator empowers teams to meet this demand by providing a stable and reliable method for automating complex user flows, verifying critical functionalities, and identifying regressions early in the development cycle.
Understanding UiAutomator: The Core Framework
UiAutomator is not just a library.
It’s a comprehensive framework designed for UI testing across different Android applications.
It operates at the system level, meaning it can interact with any UI element on the device, regardless of which application owns it.
This contrasts with instrumentation tests that typically run within the context of a single app. How to perform test automation with circleci
What is UiAutomator and Its Purpose?
UiAutomator is a Java-based UI testing framework provided by Google as part of the Android SDK.
Its primary purpose is to enable automated functional UI testing of Android applications.
Unlike other testing frameworks like Espresso, which focuses on white-box testing knowing the app’s internal structure and interacting with views directly, UiAutomator excels at black-box testing.
This means you interact with the UI elements as an end-user would, without needing access to the application’s source code or internal implementation details.
It’s particularly useful for testing interactions between multiple applications, verifying system-level behaviors like navigating through settings, responding to notifications, or interacting with system dialogues, and performing end-to-end user journey tests across various apps on a device. Run tests in puppeteer with firefox
With the increasing complexity of modern Android applications, which often involve integrations with other apps or system services, UiAutomator provides a vital capability for comprehensive testing.
Key Components of the UiAutomator Framework
The UiAutomator framework comprises several core components that work together to enable robust UI automation:
UiDevice
: This is the central object that represents the state of the device. It provides methods to interact with the device as a whole, such as pressing the Home button, Back button, opening the notification shade, rotating the screen, or taking screenshots. It’s the entry point for all UiAutomator tests. For instance,UiDevice.getInstanceInstrumentationRegistry.getInstrumentation
is the standard way to get aUiDevice
instance.UiObject
: Represents a single UI element on the device. Once you locate a UI element using aUiSelector
, you get aUiObject
instance, which you can then use to perform actions likeclick
,setText
,swipe
,longClick
, or retrieve its properties likegetText
orgetContentDescription
.UiObject
is immutable. once created, it references the element that matched theUiSelector
at the time of its creation.UiObject2
: Introduced in UiAutomator 2.0 part of AndroidX Test,UiObject2
is an improved version ofUiObject
. It offers better performance, more robust element identification, and a fluent API usingBy
selectors. UnlikeUiObject
,UiObject2
is not immutable. it automatically re-locates the UI element if the UI changes. This makes it more resilient to dynamic UIs.UiSelector
: Used withUiObject
to define criteria for locating a specific UI element. It allows you to build complex queries based on properties liketext
,resource-id
,class
,description
,checkable
,clickable
,enabled
,focused
,packageName
,index
, and more. You can chain multipleUiSelector
methods to narrow down your search, such asnew UiSelector.text"Settings".className"android.widget.TextView"
.By
: Used withUiObject2
,By
provides a more modern and readable way to define selectors, similar to CSS selectors or XPath. Examples includeBy.res"com.android.settings:id/settings_search_bar"
,By.text"Wi-Fi"
,By.desc"Navigate up"
. It supports more advanced matching likeBy.textContains
orBy.clickabletrue
.Until
: This class, part of the UiAutomator 2.0 API, provides conditions for waiting for UI changes. Instead of using arbitraryThread.sleep
calls,Until
allows you to wait for specific conditions to be met, such as an object appearingUntil.hasObject
, an object disappearingUntil.gone
, or a specific text becoming visible. This makes tests more robust and less prone to flakiness due to timing issues. For instance,device.waitUntil.hasObjectBy.text"Wi-Fi", 5000
waits up to 5 seconds for the “Wi-Fi” text to appear.InstrumentationRegistry
: Provides access to theInstrumentation
object, which is the bridge between your test code and the Android system. It’s used to obtain theContext
of your application and, crucially, to get theUiDevice
instance.UiAutomatorViewer
: This graphical tool is essential for inspecting the UI hierarchy of an app running on a device or emulator. It provides a visual representation of the UI elements, displaying their properties likeresource-id
,text
,content-desc
, andclass
. This information is critical for constructing accurateUiSelector
orBy
queries to locate elements in your test scripts.
Advantages and Limitations of UiAutomator
Like any tool, UiAutomator has its strengths and weaknesses:
Advantages:
- Black-Box Testing: It’s excellent for testing an app from an end-user perspective, without needing access to the app’s source code. This is particularly valuable for pre-release testing or verifying third-party app interactions.
- Cross-App Interaction: Its key strength is the ability to interact with UI elements across different applications and system components e.g., settings, notifications, system dialogues. This makes it suitable for complex user journeys that involve multiple apps.
- System-Level Control: It provides methods to control device-level actions like pressing system buttons Home, Back, Recent Apps, opening notifications, rotating the screen, and even executing shell commands, offering comprehensive device manipulation.
- Robustness for UI Changes:
UiObject2
andBy
selectors, combined with theUntil
class, offer better resilience to minor UI changes compared to older methods, making tests more stable. - Official Google Support: Being part of the Android SDK and AndroidX Test, it benefits from continuous updates and support from Google.
- Widely Adopted: Many enterprises and testing teams utilize UiAutomator for their large-scale UI automation needs, indicating its reliability and effectiveness.
Limitations: How to install testng in eclipse
- No Access to App Internals: Since it’s a black-box framework, UiAutomator cannot directly access internal app data, databases, or private methods. For detailed white-box testing, Espresso is often preferred.
- Flakiness: While
Until
helps, UI automation can still be prone to flakiness due to network delays, unexpected pop-ups, or minor UI rendering differences across devices. Careful handling of waits and retries is necessary. - Performance Overhead: Compared to unit tests or even some instrumentation tests, UI automation tests can be slower due to the overhead of interacting with the UI and device.
- Steep Learning Curve for beginners: While Java is widely known, understanding the nuances of UI element identification, handling synchronization issues, and managing test state can be challenging for newcomers.
- Limited Customization for Non-Standard UI: For highly custom or non-standard UI elements e.g., complex custom views that don’t expose standard Android properties, finding reliable selectors can be difficult or even impossible.
- Reporting: UiAutomator itself provides basic JUnit test results. Integrating with more advanced reporting tools often requires external libraries or custom implementations.
In summary, UiAutomator is an excellent choice for functional UI testing, especially for scenarios involving system interactions and multi-app flows.
However, for unit testing or deeply integrated white-box testing within a single application, other frameworks like Espresso might be more suitable.
Often, a combination of testing strategies unit, integration, and UI tests using various frameworks provides the most comprehensive coverage.
Setting Up Your Development Environment for UiAutomator
Properly configuring your development environment is the foundational step for any successful automation endeavor.
For UiAutomator, this involves installing essential software and setting up necessary paths. Tutorials
Skipping any of these steps can lead to frustrating errors and delays.
Installing Android Studio and SDK Tools
Android Studio is the official Integrated Development Environment IDE for Android app development, and it comes bundled with the Android SDK Software Development Kit and its essential tools, including those required for UiAutomator.
- Download Android Studio:
- Navigate to the official Android Developers website: https://developer.android.com/studio
- Download the appropriate version for your operating system Windows, macOS, or Linux. The file size is significant, so ensure you have a stable internet connection.
- Install Android Studio:
- Windows: Run the
.exe
installer. Follow the on-screen prompts. It’s recommended to install for “Anyone who uses this computer” for easier path management. - macOS: Drag the downloaded
Android Studio.app
to your Applications folder. - Linux: Extract the downloaded
.zip
file to a suitable location e.g.,/opt/android-studio
. Then, navigate to thebin
directory within the extracted folder and run./studio.sh
.
- Windows: Run the
- Initial Setup Wizard:
- Upon first launch, Android Studio will guide you through a setup wizard.
- Choose a “Standard” installation, which includes the necessary SDK components, Android Virtual Device AVD manager, and other essential tools.
- Accept the license agreements.
- Android Studio will download and install the required SDK components. This process might take some time depending on your internet speed.
- Verify SDK Location:
- Once Android Studio is set up, you can find your Android SDK location by going to
File > Project Structure > SDK Location
orAndroid Studio > Settings > Appearance & Behavior > System Settings > Android SDK
on macOS. - Typical default locations:
- Windows:
C:\Users\YourUser\AppData\Local\Android\Sdk
- macOS:
~/Library/Android/sdk
- Linux:
~/Android/Sdk
or wherever you chose to extract it.
- Windows:
- Important: Note this path down, as you’ll need it for environment variables.
- Once Android Studio is set up, you can find your Android SDK location by going to
Configuring Environment Variables ANDROID_HOME, PATH
Setting up environment variables ensures that your operating system can locate the Android SDK tools from any directory in your terminal or command prompt, which is crucial for running commands like adb
or uiautomatorviewer
.
- Set
ANDROID_HOME
orANDROID_SDK_ROOT
:- This variable should point to the root directory of your Android SDK installation.
- Windows:
- Right-click “This PC” or “My Computer” -> “Properties” -> “Advanced system settings” -> “Environment Variables…”.
- Under “System variables”, click “New…”.
- Variable name:
ANDROID_HOME
- Variable value: Your SDK path, e.g.,
C:\Users\YourUser\AppData\Local\Android\Sdk
- Click “OK” on all windows to save.
- macOS / Linux:
- Open your terminal.
- Open your shell configuration file e.g.,
~/.bash_profile
,~/.zshrc
,~/.bashrc
. - Add the following lines:
export ANDROID_HOME=$HOME/Library/Android/sdk # For macOS default # OR # export ANDROID_HOME=/opt/android-sdk # If you installed elsewhere export PATH=$PATH:$ANDROID_HOME/platform-tools:$ANDROID_HOME/tools:$ANDROID_HOME/tools/bin
- Save the file and then source it:
source ~/.bash_profile
or your respective file.
- Add
platform-tools
andtools/bin
toPATH
:- The
platform-tools
directory containsadb
Android Debug Bridge, which is essential for communicating with devices. - The
tools/bin
directory containsuiautomatorviewer
.- In the “Environment Variables” window, find the
Path
variable under “System variables” and click “Edit…”. - Click “New” and add the full path to
platform-tools
e.g.,C:\Users\YourUser\AppData\Local\Android\Sdk\platform-tools
. - Click “New” again and add the full path to
tools\bin
e.g.,C:\Users\YourUser\AppData\Local\Android\Sdk\tools\bin
. - Click “OK” on all windows.
- In the “Environment Variables” window, find the
- macOS / Linux: Already covered in the
ANDROID_HOME
step above within thePATH
export.
- The
Verifying Installation with ADB
After setting up environment variables, it’s crucial to verify that adb
Android Debug Bridge is accessible and working correctly.
adb
is the primary command-line tool used to communicate with Android devices and emulators. Functional and non functional testing checklist
- Connect a Device or Start an Emulator:
- Physical Device:
- Enable Developer options on your Android device Go to
Settings > About phone
and tap “Build number” seven times. - Enable USB debugging within Developer options.
- Connect your device to your computer via a USB cable.
- When prompted on your device, allow USB debugging for your computer.
- Enable Developer options on your Android device Go to
- Android Emulator:
- In Android Studio, go to
Tools > Device Manager
orAVD Manager
in older versions. - Click “Create device” and follow the prompts to create a new Android Virtual Device AVD. Choose a device definition and a system image.
- Once created, select your AVD and click the “Play” button to launch it.
- In Android Studio, go to
- Physical Device:
- Open a Terminal/Command Prompt:
-
Type
adb devices
and press Enter. -
Expected Output: You should see a list of connected devices/emulators.
List of devices attached
emulator-5554 device- daemon not running. starting now at tcp:5037
- daemon started successfully
R58N64M87LM device
If you see your device/emulator listed as “device” or “offline” initially, which might resolve itself, your
adb
setup is correct.
-
If you get “command not found” or an empty list, double-check your PATH
variable and USB debugging settings.
This systematic setup ensures that all the necessary tools are in place and correctly configured, providing a stable foundation for your UiAutomator automation efforts. What is android ui testing
Inspecting UI Elements with UiAutomator Viewer
One of the most critical steps in creating effective UiAutomator tests is accurately identifying the UI elements you want to interact with.
This is where the UiAutomator Viewer comes into play.
It’s a graphical tool that provides a snapshot of the current UI hierarchy on your device, revealing the properties of every visible element.
Launching and Using UiAutomator Viewer
The UiAutomator Viewer is part of the Android SDK and is typically located in the tools/bin
directory.
- Ensure a Device/Emulator is Connected:
- Make sure your Android device is connected via USB with USB debugging enabled, or an Android emulator is running. You can verify this by running
adb devices
in your terminal.
- Make sure your Android device is connected via USB with USB debugging enabled, or an Android emulator is running. You can verify this by running
- Navigate to the
tools/bin
Directory:- Open your terminal or command prompt.
- Change directory to the
tools/bin
folder within your Android SDK installation.- Windows:
cd %ANDROID_HOME%\tools\bin
orcd C:\Users\YourUser\AppData\Local\Android\Sdk\tools\bin
- macOS/Linux:
cd $ANDROID_HOME/tools/bin
orcd ~/Library/Android/sdk/tools/bin
- Windows:
- Launch UiAutomator Viewer:
- Run the appropriate command:
- Windows:
uiautomatorviewer.bat
- macOS/Linux:
./uiautomatorviewer
- Windows:
- A new window titled “UI Automator Viewer” will open.
- Run the appropriate command:
- Capture a Screenshot:
- On your connected device/emulator, navigate to the screen of the app you want to inspect.
- In the UiAutomator Viewer window, click the “Device Screenshot” button it looks like a phone icon with a camera, usually the first icon on the left toolbar.
- The viewer will capture the current screen, pull its UI hierarchy, and display it in the main window.
- Explore the UI:
- The UiAutomator Viewer window is divided into several panes:
- Screenshot Pane Left: Shows the visual representation of the screen. As you hover over elements, their boundaries will be highlighted.
- UI Hierarchy Pane Top Right: Displays the XML representation of the UI elements in a tree structure. This is where you can see the nesting of elements.
- Node Detail Pane Bottom Right: When you select an element in either the screenshot or the hierarchy pane, this pane displays all the properties of that element, such as
resource-id
,text
,class
,content-desc
,checkable
,clickable
,enabled
,focused
,packageName
, and its bounds.
- The UiAutomator Viewer window is divided into several panes:
Identifying Key Properties for Locating Elements resource-id, text, content-desc, class
The properties displayed in the Node Detail Pane are crucial for constructing UiSelector
or By
selectors in your automation scripts. Create mobile app testing scenarios
Here’s a breakdown of the most commonly used and reliable ones:
-
resource-id
: This is often the most stable and preferred way to identify an element. It’s unique within an application’s scope though not necessarily globally unique across all apps. It typically follows the formatpackage_name:id/element_id
e.g.,com.example.myapp:id/login_button
. If an element has aresource-id
, prioritize using it.- Example in UiAutomator Viewer:
resource-id: "com.android.settings:id/settings_search_bar"
- Corresponding code:
UiSelector
:new UiSelector.resourceId"com.android.settings:id/settings_search_bar"
By
:By.res"com.android.settings:id/settings_search_bar"
orBy.res"settings_search_bar"
if the package name is implicit
- Example in UiAutomator Viewer:
-
text
: This property contains the visible text displayed on a UI element e.g., “Login”, “Settings”, “Wi-Fi”. It’s useful when elements don’t have aresource-id
or when you want to target elements based on their user-perceived labels. However, be cautious as text can change due to localization different languages or dynamic content.- Example in UiAutomator Viewer:
text: "Wi-Fi"
UiSelector
:new UiSelector.text"Wi-Fi"
ornew UiSelector.textContains"Wi-Fi"
By
:By.text"Wi-Fi"
orBy.textContains"Wi-Fi"
- Example in UiAutomator Viewer:
-
content-desc
Content Description: This property is primarily used for accessibility purposes, providing a textual description of the element for screen readers. For image buttons or icons that don’t have visible text,content-desc
is often the most reliable identifier. Developers should ideally set meaningful content descriptions for all interactive elements.- Example in UiAutomator Viewer:
content-desc: "More options"
for a three-dot menu iconUiSelector
:new UiSelector.description"More options"
ornew UiSelector.descriptionContains"options"
By
:By.desc"More options"
orBy.descContains"options"
- Example in UiAutomator Viewer:
-
class
: This property indicates the Android UI class of the element e.g.,android.widget.Button
,android.widget.TextView
,android.widget.EditText
,android.view.ViewGroup
,androidx.recyclerview.widget.RecyclerView
. While not unique enough on its own to identify a specific element, it’s very useful for filtering searches or finding a group of similar elements. It’s often combined with other selectors. Web application testing- Example in UiAutomator Viewer:
class: "android.widget.Button"
UiSelector
:new UiSelector.className"android.widget.Button"
By
:By.clazz"android.widget.Button"
- Example in UiAutomator Viewer:
Tips for Using UiAutomator Viewer:
- Hierarchy is Key: Pay attention to the element’s position within the UI hierarchy. Sometimes, combining a parent element’s property with a child’s
index
or another property is the most robust way to locate it. - Unique Identifiers First: Always try
resource-id
first. If not available, usecontent-desc
. If neither is available, usetext
. Only useclass
orindex
as a last resort or in combination with other, more specific selectors. - Dynamic Elements: Be aware that
text
andcontent-desc
can change. If an element’s text changes based on app state or language, usingtextContains
or combining withresource-id
if present on a parent might be necessary. - Bounds: The
bounds
property shows the coordinates of the element on the screen. While you can click using coordinates, it’s highly discouraged for general automation as it’s extremely brittle and device-dependent. Stick to property-based selectors. - Refresh Often: If the UI changes on your device, re-capture the screenshot in UiAutomator Viewer to get the updated hierarchy.
Mastering the UiAutomator Viewer is fundamental.
It transforms the often-abstract process of UI element identification into a visual and intuitive task, dramatically speeding up the development of reliable UiAutomator tests.
Writing Your First UiAutomator Test Script
Once your environment is set up and you’re comfortable with UiAutomator Viewer, it’s time to write your first actual test script.
This section will guide you through creating a basic project, adding dependencies, and structuring a simple test case. Test aab file on android device
Project Setup in Android Studio
To begin, you need an Android project to house your UiAutomator tests.
While UiAutomator tests run separately from your app’s main code, Android Studio provides the best environment for managing dependencies and running tests.
- Create a New Android Studio Project:
- Open Android Studio.
- Select “New Project”.
- Choose “Empty Activity” template or any other, as the UI of the app itself isn’t directly relevant for UiAutomator setup.
- Click “Next”.
- Configure your project:
- Name:
UiAutomatorDemo
or any descriptive name - Package name:
com.example.uiautomatordemo
- Save location: Choose a suitable directory.
- Language:
Java
UiAutomator tests are typically written in Java - Minimum SDK: Keep it at a reasonable level e.g., API 21 or higher to ensure compatibility with modern UiAutomator versions.
- Name:
- Click “Finish”. Android Studio will set up your project and sync Gradle.
Adding UiAutomator Dependencies to build.gradle
For your project to recognize and compile UiAutomator classes, you need to add the necessary dependencies to your app/build.gradle
file.
These dependencies belong in the androidTestImplementation
configuration, indicating they are for instrumentation tests that run on a device.
- Open
app/build.gradle
: In the Android Studio Project view, navigate toapp > build.gradle Module :app
. - Add Dependencies: Locate the
dependencies
block and add the following lines. Always check for the latest stable versions from the AndroidX documentation or Maven Central.dependencies { // ... other dependencies e.g., for your main app // UiAutomator dependencies androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' // Core UiAutomator library androidTestImplementation 'androidx.test:runner:1.5.2' // AndroidJUnitRunner, essential for running tests androidTestImplementation 'androidx.test:rules:1.5.0' // For test rules, like ActivityTestRule though less common for pure UiAutomator androidTestImplementation 'androidx.test.ext:junit:1.1.5' // For JUnit4 assertions and annotations // Optional: If you need to include the actual app code in your test project, // which is often useful for launching your own app from within the test // implementation project":app" // If your test is in a separate module * Note on Versions: As of late 2023 / early 2024, `uiautomator:2.2.0`, `runner:1.5.2`, `rules:1.5.0`, and `junit:1.1.5` are common stable versions. Always consult the official AndroidX Test documentation for the absolute latest.
- Sync Gradle: After adding the dependencies, a prompt “Sync Now” will appear at the top of the editor window. Click it to synchronize your project with the new Gradle configuration. This downloads the libraries.
Basic Test Structure and Example Test Case
Now, let’s create a simple test to open the device’s Settings app and verify a specific element. Test case prioritization
-
Create a Test Class:
- In Android Studio, navigate to
app/src/androidTest/java/com/example/uiautomatordemo
replacecom.example.uiautomatordemo
with your actual package name. - Right-click on the package folder ->
New
->Java Class
. - Name the class
SettingsTest
or a descriptive name for your test suite.
- In Android Studio, navigate to
-
Write the Test Code:
package com.example.uiautomatordemo.
// Make sure this matches your project’s androidTest package
import static org.junit.Assert.fail. // For demonstration of failure
public class SettingsTest {
private static final String SETTINGS_PACKAGE = "com.android.settings".
private static final int LAUNCH_TIMEOUT = 5000. // 5 seconds
/
* Setup method to initialize UiDevice and launch the Settings app before each test.
*/
public void setUp {
// Get an instance of UiDevice
assertNotNull"UiDevice instance should not be null", device.
// Start from the home screen
// Launch the Settings app
// Use 'am start' shell command for robust app launch
try {
device.executeShellCommand"am start -n " + SETTINGS_PACKAGE + "/.Settings".
// Wait for the Settings app to be visible
device.waitUntil.hasObjectBy.pkgSETTINGS_PACKAGE.depth0, LAUNCH_TIMEOUT.
System.out.println"Settings app launched successfully.".
} catch Exception e {
fail"Failed to launch Settings app: " + e.getMessage.
* Test case: Verify that the "Network & internet" or "Connected devices" option is visible in Settings.
* This adapts to slight variations in Android Settings UI across versions.
public void testNavigateToNetworkSettings {
// Look for "Network & internet" modern Android or "Connected devices" older Android
UiObject2 networkInternetOption = device.findObjectBy.text"Network & internet".
if networkInternetOption == null {
networkInternetOption = device.findObjectBy.text"Connected devices".
// Assert that one of the options is found
assertTrue"Could not find 'Network & internet' or 'Connected devices' option",
networkInternetOption != null && networkInternetOption.exists.
// Click the found option
networkInternetOption.click.
fail"Failed to click network option: " + e.getMessage.
// Wait for the next screen to load, asserting for a common element like "Internet" or "Bluetooth"
boolean internetScreenLoaded = device.waitUntil.hasObjectBy.text"Internet", LAUNCH_TIMEOUT.
boolean bluetoothScreenLoaded = device.waitUntil.hasObjectBy.text"Bluetooth", LAUNCH_TIMEOUT.
assertTrue"Neither 'Internet' nor 'Bluetooth' screen loaded after clicking network option",
internetScreenLoaded || bluetoothScreenLoaded.
System.out.println"Navigated to network settings successfully.".
// Optional: Go back to Settings home
device.pressBack.
device.waitUntil.hasObjectBy.pkgSETTINGS_PACKAGE.depth0, LAUNCH_TIMEOUT. // Wait for Settings app to reappear
* Another test case: Test the search bar in Settings.
public void testSettingsSearchBar throws Exception {
// Find the search bar using resource ID more reliable or content description
UiObject2 searchBar = device.findObjectBy.resSETTINGS_PACKAGE, "settings_search_bar".
if searchBar == null { // Fallback if resource ID isn't available or changes
searchBar = device.findObjectBy.desc"Search settings".
assertNotNull"Settings search bar not found", searchBar.
assertTrue"Search bar should be clickable", searchBar.isClickable.
// Click the search bar
searchBar.click.
// Type text into the search input field
UiObject2 searchInput = device.findObjectBy.res"com.android.settings", "search_src_text".
assertNotNull"Search input field not found", searchInput.
String searchText = "display".
searchInput.setTextsearchText.
// Wait for search results to appear e.g., "Display" option
assertTrue"Display search result not found after typing",
device.waitUntil.hasObjectBy.text"Display", LAUNCH_TIMEOUT.
System.out.println"Search bar tested successfully for: " + searchText.
Explanation of the Code: Challenges in test automation
@RunWithAndroidJUnit4.class
: This annotation tells JUnit to useAndroidJUnit4
as the test runner, which is required for running instrumentation tests on an Android device.@Before
: This annotation marks a method to be run before each test method in the class. It’s used here to initializeUiDevice
and launch the Settings app, ensuring each test starts from a clean, known state.UiDevice.getInstanceInstrumentationRegistry.getInstrumentation
: This line gets the singletonUiDevice
instance, which is your main interface to interact with the device.InstrumentationRegistry.getInstrumentation
provides theInstrumentation
object needed for this.device.pressHome
: Simulates pressing the physical Home button, ensuring the device is on the home screen before launching an app.device.executeShellCommand"am start -n " + PACKAGE_NAME + "/.Settings"
: This is a powerful way to launch an app.am start
is an Android shell command that launches an activity.-n
specifies the component name package name/activity name. This is more reliable thancontext.startActivity
for UiAutomator tests.device.waitUntil.hasObjectBy.pkgSETTINGS_PACKAGE.depth0, LAUNCH_TIMEOUT
: This is a crucial synchronization step. It waits up toLAUNCH_TIMEOUT
milliseconds 5 seconds for an object belonging to theSETTINGS_PACKAGE
to appear at depth 0 meaning the root of the UI hierarchy for that package, confirming the app has launched.By.text"Network & internet"
orBy.resSETTINGS_PACKAGE, "settings_search_bar"
: These areBy
selectors used withUiObject2
to find elements.By.text
finds by visible text,By.res
finds by resource ID.device.findObjectBy.text"Network & internet"
: This method searches for aUiObject2
matching the givenBy
selector. It returnsnull
if the object is not found.networkInternetOption.click
: Performs a click action on the foundUiObject2
.assertTrue"Message", condition
: Standard JUnit assertion to verify a condition. If the condition is false, the test fails and displays the provided message.- Error Handling: Basic
try-catch
blocks are included for operations that might throw exceptions, like launching an app.fail
is used to explicitly fail the test if an unrecoverable error occurs. UiObject2.setTextString text
: Used to type text into an editable field.
This example provides a solid foundation.
Remember to use UiAutomatorViewer
frequently to inspect your target app’s UI and obtain the correct selectors for its elements.
Advanced UiAutomator Techniques
Once you’ve mastered the basics, you’ll encounter scenarios that require more sophisticated techniques to create robust and reliable automation scripts.
Advanced UiAutomator features help handle dynamic content, complex gestures, and ensure test stability.
Handling Dynamic UI Elements and Waiting Strategies
One of the biggest challenges in UI automation is dealing with dynamic elements whose properties or presence might change over time. Introduction
This includes elements that appear after a delay, disappear, or change their text/state.
Relying on fixed Thread.sleep
calls is a recipe for flaky tests.
UiAutomator provides better synchronization mechanisms.
-
Using
Until
for Smart Waits:The
Until
class part of UiAutomator 2.0 is the cornerstone of reliable waiting strategies. Appium with java
Instead of arbitrary delays, you wait for a specific UI condition to be met.
* Waiting for an object to appear:
```java
// Wait up to 10 seconds for an object with resource ID 'my_button' to appear
boolean buttonExists = device.waitUntil.hasObjectBy.res"com.example.myapp:id/my_button", 10000.
assertTrue"My button did not appear in time", buttonExists.
UiObject2 myButton = device.findObjectBy.res"com.example.myapp:id/my_button".
myButton.click.
* Waiting for an object to disappear:
// Wait up to 5 seconds for a loading spinner to disappear
boolean spinnerGone = device.waitUntil.goneBy.desc"Loading spinner", 5000.
assertTrue"Loading spinner did not disappear", spinnerGone.
* Waiting for text to change:
UiObject2 statusText = device.findObjectBy.res"com.example.myapp:id/status_message".
// Wait up to 7 seconds for the status text to change to "Success"
boolean textChanged = device.waitUntil.textMatchesBy.res"com.example.myapp:id/status_message", "Success", 7000.
assertTrue"Status message did not change to 'Success'", textChanged.
* Waiting for a window update: Useful for confirming navigation or screen transitions.
// After clicking a button that opens a new activity
device.clickmyButton.getBounds.centerX, myButton.getBounds.centerY. // Click using coordinates
device.waitUntil.hasWindowContentChanged5000. // Wait for window content to change within 5 seconds
* Chaining `Until` conditions: You can combine conditions using `Until.or` or `Until.and`.
-
Handling Scrollable Lists and RecyclerViews:
Apps often feature long lists or grids implemented using
RecyclerView
orScrollView
. You can’t always see all elements in one screen. UiAutomator provides methods for scrolling.-
Scrolling to an element: If you need to find an element that might be off-screen within a scrollable container, you can scroll until it’s visible.
// Assume ‘myScrollView’ is a UiObject or UiObject2 representing the scrollable container Playwright tutorial
// and ‘targetText’ is the text of the element you want to find.
// Using UiObject older API, more direct for scrolling to text
UiObject scrollableList = device.findObjectnew UiSelector.scrollabletrue.
ScrollableList.scrollIntoViewnew UiSelector.text”Target Item Text”.
// Then, find and click the elementUiObject targetItem = device.findObjectnew UiSelector.text”Target Item Text”.
AssertTrue”Target item not found after scrolling”, targetItem.exists.
targetItem.click.// Using UiObject2 requires finding the scrollable object first
UiObject2 recyclerView = device.findObjectBy.clazz”androidx.recyclerview.widget.RecyclerView”.
if recyclerView != null {// Scroll forward until "Target Item Text" is visible or end is reached boolean scrolled = recyclerView.scrollUntil Until.hasObjectBy.text"Target Item Text", device.findObjectBy.text"Target Item Text", // Element to find 1000 // Timeout for each scroll attempt assertTrue"Could not scroll to target item", scrolled. device.findObjectBy.text"Target Item Text".click.
-
Swiping within an object:
UiObject2 viewPager = device.findObjectBy.res”com.example.myapp:id/view_pager”.
if viewPager != null {viewPager.swipeDirection.LEFT, 1.0f. // Swipe left across the entire width // Or specific distance: viewPager.swipeDirection.LEFT, 0.7f, 500. // 70% width, 500ms duration
-
Performing Complex Gestures Swipe, Pinch, Drag
UiAutomator provides fine-grained control over touch gestures, which are essential for testing map applications, image viewers, or any app with interactive custom views.
-
Swiping:
// Simple swipe across the entire screenDevice.swipe500, 1000, 500, 200, 10. // StartX, StartY, EndX, EndY, Steps speed
// Swipe from left to right e.g., to open a navigation drawer
Device.swipe0, device.getDisplayHeight / 2, device.getDisplayWidth, device.getDisplayHeight / 2, 50.
UiObject2
offers more intuitive swipe methods:UiObject2 targetElement = device.findObjectBy.res”com.example.myapp:id/image_viewer”.
TargetElement.swipeDirection.LEFT, 0.7f. // Swipe 70% of the element’s width to the left
-
Pinch-to-Zoom:
The
pinchIn
andpinchOut
methods onUiObject2
allow simulating multi-touch gestures.UiObject2 mapElement = device.findObjectBy.res”com.example.myapp:id/map_view”.
if mapElement != null {mapElement.pinchIn0.7f, 10. // Pinch in by 70% with 10 steps // To zoom out mapElement.pinchOut0.7f, 10. // Pinch out by 70% with 10 steps
-
Dragging:
Simulating a drag-and-drop operation.UiObject2 draggableItem = device.findObjectBy.res”com.example.myapp:id/draggable_item”.
UiObject2 dropTarget = device.findObjectBy.res”com.example.myapp:id/drop_target”.
If draggableItem != null && dropTarget != null {
draggableItem.dragdropTarget.getVisibleCenter, 100. // Drag to center of target in 100 steps
Integrating with JUnit and Test Runners
UiAutomator tests are standard JUnit tests, which means you can leverage JUnit’s powerful annotations and assertions for structuring your tests and validating outcomes.
@RunWithAndroidJUnit4.class
: As seen before, this annotation on your test class is crucial. It tells the test runner to use the AndroidJUnit4 runner, which understands how to execute instrumentation tests on a device.@Before
and@After
:-
@Before
methods run before each test method, ideal for setup e.g., initializingUiDevice
, launching the app, resetting app state. -
@After
methods run after each test method, ideal for teardown e.g., closing the app, logging out, cleaning up data.
@After
public void tearDown {// Example: Go back to home screen after each test
if device != null {// You might also force stop the app for a clean start next time // try { device.executeShellCommand"am force-stop " + SETTINGS_PACKAGE. } catch Exception e {}
-
@BeforeClass
and@AfterClass
:- Methods annotated with
@BeforeClass
run once before all tests in the class. Must bestatic
. Useful for expensive, one-time setup e.g., installing a prerequisite app if tests involve multi-app flows. - Methods annotated with
@AfterClass
run once after all tests in the class. Must bestatic
. Useful for global teardown e.g., uninstalling an app.
- Methods annotated with
- Assertions:
- Use
org.junit.Assert
methods ororg.junit.jupiter.api.Assertions
if using JUnit 5 for validating test outcomes. assertTrue
,assertFalse
,assertEquals
,assertNotNull
,assertNull
,fail
.- Example:
assertTrue"Login button not found after navigating", device.findObjectBy.text"LOGIN".exists.
- Use
- Parameterized Tests Advanced: For testing the same flow with different data inputs e.g., different user credentials, different search queries, you can use JUnit’s parameterized tests or frameworks like
Parameterized
runner. This reduces code duplication.
By incorporating these advanced techniques, your UiAutomator tests will become more resilient, efficient, and capable of automating complex user interactions, leading to more thorough testing and higher quality applications.
Best Practices and Tips for Robust UiAutomator Tests
Creating reliable and maintainable UI automation tests is an art as much as it is a science.
Flaky tests tests that pass sometimes and fail other times without code changes are a common headache.
Adhering to best practices can significantly improve the stability, speed, and maintainability of your UiAutomator test suite.
Designing Maintainable Test Suites
A well-structured test suite is easier to understand, debug, and expand.
- Page Object Model POM: This is arguably the most important design pattern in UI automation.
-
Concept: For each distinct screen or major component in your application, create a corresponding “Page Object” class.
-
Encapsulation: Each Page Object encapsulates the UI elements locators and the user interactions methods available on that screen.
-
Example:
// LoginPage.java
public class LoginPage {
private UiDevice device.public LoginPageUiDevice device { this.device = device. }
public UiObject2 getUsernameField { return device.findObjectBy.res”com.myapp:id/username_input”. }
public UiObject2 getPasswordField { return device.findObjectBy.res”com.myapp:id/password_input”. }
public UiObject2 getLoginButton { return device.findObjectBy.res”com.myapp:id/login_button”. }
public HomePage loginString username, String password throws Exception {
getUsernameField.setTextusername.
getPasswordField.setTextpassword.
getLoginButton.click.device.waitUntil.hasObjectBy.res”com.myapp:id/home_dashboard”, 5000.
return new HomePagedevice. // Return the next page object
// In your test class:
public void testSuccessfulLogin {LoginPage loginPage = new LoginPagedevice. HomePage homePage = loginPage.login"testuser", "password123". assertTruehomePage.getDashboardTitle.exists.
-
Benefits:
- Readability: Tests become more readable as they express user actions rather than low-level UI interactions.
- Maintainability: If a UI element’s ID or text changes, you only need to update it in one place the Page Object rather than across multiple test cases.
- Reusability: Page Object methods can be reused across different test scenarios.
-
- Clear Naming Conventions: Use descriptive names for test classes, methods, and variables.
LoginTest.java
,testSuccessfulLogin
,testInvalidCredentials
homeScreen
,searchButton
,resultsList
- Modularization: Break down complex test flows into smaller, manageable methods or utility classes. For example, a
HelperUtils
class for common actions likelaunchApp
,grantPermissions
. - Data-Driven Testing: Separate test data from test logic. Use external sources CSV, JSON, properties files for test data, especially for scenarios like login with multiple user types or testing different configurations.
Robust Element Identification Strategies
The strength of your test lies in its ability to reliably find UI elements.
- Prioritize
resource-id
: As discussed,resource-id
is usually the most stable and unique identifier for an element. - Use
content-desc
for Accessibility: For icon-only buttons or images,content-desc
used for accessibility is the next best choice. Encourage developers to add meaningful content descriptions. - Use
text
cautiously: While convenient, text can change with localization, dynamic content, or minor UI tweaks. UsetextContains
for partial matches, but always prefer more specific selectors if available. - Combine Selectors: Often, a single property isn’t enough. Combine
class
withtext
,content-desc
, orindex
to narrow down the search.new UiSelector.className"android.widget.TextView".text"Settings"
By.clazz"android.widget.Button".text"Login"
- Avoid
index
andbounds
unless necessary:index
: Using an element’s index within a parentchild.index0
is brittle. If the order of elements changes, your test breaks. Only use it when no other unique identifier is available and the order is guaranteed to be static.bounds
coordinates: Clicking or interacting with elements by their screen coordinatesdevice.clickx, y
is extremely fragile. Screen resolutions, device sizes, and even small UI layout changes will break these tests. Only use for highly specific, non-generalizable gestures e.g., clicking a precise point on a canvas if no other option exists.
- Be resilient to changes: When using
UiObject2
withBy
selectors, the framework often re-locates elements, making it more resilient. However, if the UI structure changes significantly, your selectors will need updates.
Effective Synchronization and Error Handling
Flakiness is the enemy of automation.
Proper synchronization and error handling are paramount.
-
Leverage
Until
Class Heavily: ReplaceThread.sleep
withdevice.waitUntil.condition, timeout
. This makes tests faster they don’t wait longer than necessary and more stable they wait just enough. -
Timeout Management: Set appropriate timeouts for
wait
methods. Too short, and tests fail prematurely. too long, and tests become slow. A good practice is to make timeouts configurable. -
Retry Mechanisms: For inherently flaky actions e.g., network calls, unexpected pop-ups, consider implementing simple retry logic.
Public boolean clickWithRetryUiObject2 element, int retries, long delayMillis {
for int i = 0. i <= retries. i++ {if element != null && element.exists && element.isClickable {
try {
element.click.
return true.
} catch Exception e {System.err.println”Click failed, retrying… ” + i + 1 + “/” + retries + 1 + “”.
try { Thread.sleepdelayMillis. } catch InterruptedException ie {}
System.err.println”Element not found or not clickable, retrying…”.
try { Thread.sleepdelayMillis. } catch InterruptedException ie {}
return false. // All retries failed -
Screenshots on Failure: Capture screenshots immediately when a test fails. This provides invaluable visual context for debugging.
// In your @After method or a custom TestWatcher
Public void captureScreenshotOnErrorTestWatcher watcher {
if watcher.failed {String screenshotPath = “/sdcard/Download/fail_screenshot_” + System.currentTimeMillis + “.png”.
device.takeScreenshotnew FilescreenshotPath.
System.out.println”Screenshot taken: ” + screenshotPath.
} catch IOException e {System.err.println”Failed to take screenshot: ” + e.getMessage.
You’d integrate this with JUnit’sTestWatcher
rule. -
Clear Assertions and Error Messages: Make sure your
assertTrue
,assertEquals
, etc., calls have descriptive messages. “Element not found” is less helpful than “Login button on sign-in screen not found after 10-second wait.”
By applying these best practices, you can transform your UiAutomator tests from brittle scripts into robust, reliable, and maintainable assets that truly contribute to app quality.
Running UiAutomator Tests and Reporting Results
After developing your UiAutomator tests, the next crucial step is to execute them and interpret the results.
UiAutomator tests are essentially Android Instrumentation tests, meaning they run on an Android device or emulator, distinct from regular JVM unit tests.
Executing Tests from Android Studio
The easiest way to run your UiAutomator tests during development is directly from Android Studio.
- Connect a Device or Start an Emulator: Ensure you have an Android device connected via USB with USB debugging enabled, or an AVD Android Virtual Device running in Android Studio.
- Open Your Test Class: Navigate to your UiAutomator test class e.g.,
SettingsTest.java
in theandroidTest
directory. - Run Options:
- Run All Tests in a Class: Click the green “Play” icon next to the test class name declaration
public class SettingsTest {
. This will run all methods annotated with@Test
within that class. - Run a Single Test Method: Click the green “Play” icon next to a specific
@Test
method. This is useful for debugging or focusing on a particular scenario.
- Run All Tests in a Class: Click the green “Play” icon next to the test class name declaration
- Select Target Device: Android Studio will prompt you to select a connected device or a running emulator. Choose your desired target.
- Observe Execution: Android Studio will build the test APK, install it on the device/emulator, and then launch the test runner. You’ll see the device screen change as your automation script interacts with the UI.
- View Results: The “Run” window in Android Studio usually at the bottom will display the test results.
- A green checkmark indicates a passed test.
- A red “X” indicates a failed test.
- You can click on a failed test to see the stack trace and assertion failure message, which helps in debugging.
Running Tests from the Command Line Gradle/ADB
For Continuous Integration CI systems, batch execution, or when you prefer a command-line interface, you can run UiAutomator tests using Gradle or direct adb
commands.
-
Using Gradle Recommended for CI/CD:
Gradle is the build automation system used by Android projects.
It’s the most robust way to run tests in a headless environment.
* Open Terminal/Command Prompt: Navigate to the root directory of your Android Studio project where build.gradle
is located.
* Run all instrumentation tests:
“`bash
./gradlew connectedAndroidTest # For macOS/Linux
gradlew.bat connectedAndroidTest # For Windows
This command compiles your app and test APKs, installs them on all connected devices/emulators, and runs all instrumentation tests including UiAutomator tests.
* Run tests in a specific module:
If your tests are in a module named `app`:
./gradlew :app:connectedAndroidTest
* Run a specific test class:
./gradlew :app:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.uiautomatordemo.SettingsTest
* Run a specific test method:
./gradlew :app:connectedAndroidTest -Pandroid.testInstrumentationRunnerArguments.class=com.example.uiautomatordemo.SettingsTest#testNavigateToNetworkSettings
* Output: Gradle will compile the tests and output the results in the console. It also generates HTML test reports in `app/build/reports/androidTests/connected/`.
-
Using ADB Advanced/Debugging:
Direct
adb
commands are useful for quickly running a test or for debugging specific test runner issues, but less common for full CI pipelines.-
Install Test APK: First, you need to build and install the test APK.
Build debug APK your app’s APK
./gradlew assembleDebug
Build debug AndroidTest APK your test APK
./gradlew assembleDebugAndroidTest
Install both APKs on the device
Adb install app/build/outputs/apk/debug/app-debug.apk
Adb install app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk
-
Execute Test:
Run all tests in the package
Adb shell am instrument -w -r -e package com.example.uiautomatordemo \
androidx.test.runner.AndroidJUnitRunner
Run a specific class
Adb shell am instrument -w -r -e class com.example.uiautomatordemo.SettingsTest \
Run a specific method
Adb shell am instrument -w -r -e class com.example.uiautomatordemo.SettingsTest#testNavigateToNetworkSettings \
-
Output:
adb
will print the raw test results to the console.
-
Interpreting Test Reports and Logs
Understanding test reports and logs is vital for debugging failures and assessing test suite quality.
- Gradle HTML Reports:
- After running
connectedAndroidTest
via Gradle, navigate toapp/build/reports/androidTests/connected/
. - Open
index.html
in your web browser. - This report provides a clear, summarized view of test runs: total tests, passed, failed, skipped, and execution time.
- You can drill down into individual test classes and methods to see detailed results, including any error messages or stack traces for failures.
- After running
- Android Studio Test Runner Output:
- The “Run” window in Android Studio provides immediate feedback.
- Passed Tests: Green checkmark.
- Failed Tests: Red “X”. Clicking on a failed test usually reveals:
- Assertion Error: Indicates where an
assertTrue
,assertEquals
, etc., failed. The message you provided in the assertion will be shown. - Stack Trace: Shows the exact line of code in your test script where the error occurred, and the call stack leading up to it. This is invaluable for pinpointing the problem.
- Assertion Error: Indicates where an
- Device Logs Logcat:
- While tests are running, or after a failure, the Android device generates system logs that can provide deeper insights.
- In Android Studio, open the “Logcat” window usually at the bottom, next to “Run”.
- Filter logs by your test package name
com.example.uiautomatordemo
in our example or by tags likeTestRunner
orSystem.out
for yourSystem.out.println
messages. - Look for
E
Error andW
Warning messages. These can indicate runtime exceptions, UI rendering issues, or app crashes that might not be directly caught by your test assertions. - Example Logcat filter:
package:mine tag:TestRunner
- Screenshots on failure: If you’ve implemented screenshot capture on test failure, review these images. They often visually explain why a test failed – maybe a dialog popped up unexpectedly, an element wasn’t rendered, or the app crashed.
By leveraging these execution methods and thoroughly analyzing the resulting reports and logs, you can efficiently develop, debug, and maintain a robust UiAutomator test suite that ensures the quality of your Android applications.
Integration with CI/CD Pipelines
Automated tests truly unlock their potential when integrated into a Continuous Integration/Continuous Delivery CI/CD pipeline.
This means tests are run automatically whenever code changes are committed, providing immediate feedback on the health of the application.
Integrating UiAutomator tests into CI/CD ensures that bugs are caught early, reducing the cost and effort of fixing them.
Why Automate Tests in CI/CD?
- Early Bug Detection: The sooner a bug is found, the cheaper and easier it is to fix. CI/CD runs tests automatically after every code commit, catching regressions almost immediately.
- Faster Feedback Loop: Developers get rapid feedback on whether their latest changes broke existing functionality.
- Improved Code Quality: Regular test execution encourages developers to write more testable code and maintain high quality.
- Reduced Manual Effort: Automation frees up QA engineers from repetitive manual testing, allowing them to focus on exploratory testing and more complex scenarios.
- Consistent Testing Environment: CI environments are typically clean and standardized, reducing “works on my machine” issues and ensuring tests run consistently.
- Confidence in Releases: A passing CI/CD pipeline gives teams confidence that a new build is stable and ready for deployment.
- Scalability: Manual testing doesn’t scale well with increasing app complexity or team size. Automation, especially in CI/CD, scales efficiently.
Setting up UiAutomator with Popular CI Platforms e.g., Jenkins, GitLab CI, GitHub Actions
The general principle for integrating UiAutomator tests into most CI/CD platforms involves setting up a virtual Android environment and executing the Gradle command to run instrumentation tests.
Common Requirements for Any CI/CD Platform:
- JDK Installation: The CI agent/runner needs Java Development Kit installed.
- Android SDK Installation: The Android SDK must be installed on the CI agent. This includes platform tools, build tools, and the Android platform version matching your app’s
compileSdkVersion
ortargetSdkVersion
. - Emulator Setup or Device Farm:
- Emulators: For CI, emulators are typically used. The CI agent needs
kvm
for Linux or HAXM for Windows/macOS enabled and properly configured for fast emulator performance. - AVD Creation: An AVD needs to be created on the CI machine.
- Device Farm Integration: For more robust and varied device testing, integrate with cloud device farms like Firebase Test Lab, BrowserStack, Sauce Labs, or AWS Device Farm. These services provide real devices and various Android versions, reducing the burden of managing physical devices or emulators on your CI server.
- Emulators: For CI, emulators are typically used. The CI agent needs
- Gradle W Gradle Wrapper: Ensure your project uses the Gradle Wrapper
gradlew
/gradlew.bat
. This makes builds self-contained and avoids issues with different Gradle versions on the CI server.
Example for a Generic Linux-based CI Runner e.g., Jenkins Agent, GitLab Runner, GitHub Actions:
A typical CI job for Android UiAutomator tests would look something like this in a script
or steps
block:
# Assume Android SDK is installed at $ANDROID_HOME and JDK is set up
# 1. Accept Android SDK Licenses crucial for CI
# This command needs to be run once per SDK install.
# It will prompt you to accept licenses. For CI, you can use:
# yes | $ANDROID_HOME/tools/bin/sdkmanager --licenses
# 2. Create and Start an Android Emulator if not using a device farm
# Example for a specific Android version e.g., API 30
# Check available system images: $ANDROID_HOME/tools/bin/sdkmanager --list | grep "system-images"
echo "Creating AVD..."
echo no | $ANDROID_HOME/tools/bin/avdmanager create avd -n test_emulator -k "system-images.android-30.google_apis.x86_64"
echo "Starting emulator..."
# Start emulator in background with a timeout
nohup $ANDROID_HOME/emulator/emulator -avd test_emulator -no-window -no-snapshot -gpu swiftshader_indirect -port 5554 > /dev/null 2>&1 &
# Wait for emulator to be fully booted
$ANDROID_HOME/platform-tools/adb wait-for-device shell 'while . do sleep 1. done.'
$ANDROID_HOME/platform-tools/adb shell input keyevent 82 # Unlock screen
echo "Emulator booted."
# 3. Grant permissions if your app requires them optional, but good practice for fresh install
# Replace com.your.package with your app's package name
# $ANDROID_HOME/platform-tools/adb shell pm grant com.your.package android.permission.READ_EXTERNAL_STORAGE
# $ANDROID_HOME/platform-tools/adb shell pm grant com.your.package android.permission.WRITE_EXTERNAL_STORAGE
# 4. Run UiAutomator tests using Gradle
echo "Running connected Android tests..."
./gradlew clean connectedAndroidTest
# 5. Collect and Publish Test Reports
# The HTML report is typically generated here: app/build/reports/androidTests/connected/index.html
# Most CI platforms have built-in steps to publish test results e.g., JUnit XML reports
# For Jenkins, you might use 'junit test-results-pattern'
# For GitLab CI/GitHub Actions, use 'artifacts' to collect reports and 'test-results' features.
# Example: cp app/build/reports/androidTests/connected/index.html /path/to/artifacts/
# 6. Stop the emulator important for resource cleanup
# $ANDROID_HOME/platform-tools/adb emu kill
Platform-Specific Examples:
-
Jenkins: Use the “Execute Shell” step for Linux agents or “Execute Windows batch command” for Windows agents. Plugins like “Android Emulator Plugin” can simplify emulator management. Use the “JUnit” Post-build Action to publish results from
app/build/test-results/testDebugUnitTest/*.xml
for unit tests orapp/build/outputs/androidTest-results/connected/*.xml
for instrumentation tests. -
GitLab CI .gitlab-ci.yml:
image: openjdk:17-jdk # Or a custom image with Android SDK variables: ANDROID_HOME: "/opt/android-sdk" # Or wherever your SDK is installed GRADLE_USER_HOME: "$pwd/.gradle" # Cache Gradle dependencies before_script: - apt-get update && apt-get install -y libkvm-dev # Install KVM for emulator - echo y | sdkmanager --install "platform-tools" "build-tools.33.0.0" "platforms.android-33" "system-images.android-33.google_apis.x86_64" - yes | sdkmanager --licenses # Accept licenses - echo "no" | avdmanager create avd -n test_emulator -k "system-images.android-33.google_apis.x86_64" - nohup emulator -avd test_emulator -no-window -no-snapshot -gpu swiftshader_indirect > /dev/null 2>&1 & - chmod +x ./gradlew # Make gradlew executable - /usr/bin/wait-for-it.sh localhost:5554 -t 120 # Wait for emulator port need wait-for-it script - adb wait-for-device shell 'while . do sleep 1. done.' - adb shell input keyevent 82 # Unlock screen test: stage: test script: - ./gradlew connectedAndroidTest artifacts: paths: - app/build/reports/androidTests/connected/ - app/build/outputs/apk/androidTest/debug/ reports: junit: app/build/outputs/androidTest-results/connected/TEST-*.xml
-
GitHub Actions .github/workflows/android.yml:
name: Android UI Automator CIon:
push:
branches:
– main
pull_request:jobs:
build-and-test:
runs-on: ubuntu-latest # Or macos-latest for HAXM
steps:
– uses: actions/checkout@v3– name: Set up JDK 17
uses: actions/setup-java@v3
with:
distribution: ‘temurin’
java-version: ’17’– name: Grant execute permission for gradlew
run: chmod +x gradlew– name: Cache Gradle packages
uses: actions/cache@v3
path: ~/.gradle/caches
key: ${{ runner.os }}-gradle-${{ hashFiles’/.gradle‘ }}restore-keys: ${{ runner.os }}-gradle
– name: AVD Cache
id: avd-cache
path: ~/.android/avdkey: avd-${{ runner.os }}-${{ matrix.api-level }}
restore-keys: |avd-${{ runner.os }}-${{ matrix.api-level }}
– name: Create AVD and start emulator
uses: reactivecircus/android-emulator-runner@v2
api-level: 30 # Or desired API level
target: google_apis # Or ‘default’ if not using Google APIs
arch: x86_64
profile: Nexus 6
emulator-build: 7858637 # Specific emulator build for stability
heap-size: 2048M
disable-animations: true
# Set other emulator options as needed
# headless: true # Already headless by default in emulator-runner– name: Run UiAutomator Tests
run: ./gradlew connectedAndroidTest– name: Upload Test Reports
uses: actions/upload-artifact@v3
name: test-resultspath: app/build/reports/androidTests/connected/
# You can also use test-results action for JUnit XML
# uses: actions/upload-artifact@v3
# with:
# name: junit-results
# path: app/build/outputs/androidTest-results/connected/
Firebase Test Lab Recommended for Diverse Device Testing:
For large-scale, diverse device testing, especially when you need to cover many Android versions and device form factors, Firebase Test Lab is an excellent option.
- Build Test APK:
gradlew assembleDebug assembleDebugAndroidTest
- Upload to Firebase Test Lab: Use the
gcloud firebase test android run
command.gcloud firebase test android run \ --type instrumentation \ --app app/build/outputs/apk/debug/app-debug.apk \ --test app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \ --device model=Pixel2,version=30,locale=en,orientation=portrait \ --timeout 10m \ --results-bucket gs://your-gcs-bucket-name \ --results-dir firebase_test_results This command will upload your app and test APKs, run them on the specified devices, and store the results including logs, screenshots, and video recordings in a Google Cloud Storage bucket.
Integrating UiAutomator tests into CI/CD pipelines transforms your testing strategy from a reactive process into a proactive one, enabling continuous quality assurance and faster, more confident software releases.
Frequently Asked Questions
What is UiAutomator used for in Android automation?
UiAutomator is an Android UI testing framework used primarily for black-box testing of Android applications.
It allows you to simulate user interactions on physical devices and emulators, focusing on functional UI testing across different applications and system components, rather than just within a single app.
Is UiAutomator better than Espresso for UI testing?
No, neither is inherently “better”. they serve different purposes. UiAutomator is for black-box, cross-app UI testing, ideal for end-to-end user journeys that involve multiple apps or system interactions. Espresso is for white-box, intra-app UI testing, designed to test the UI of a single application with direct access to its internal views, offering better speed and reliability for unit and integration UI tests. Often, a combination of both is used for comprehensive testing.
Do I need Android Studio to use UiAutomator?
Yes, Android Studio is highly recommended.
It provides the necessary Android SDK, Gradle integration, an IDE for writing Java/Kotlin code, and an intuitive way to run and debug your UiAutomator tests.
While technically you could set up the SDK and use a different IDE, Android Studio simplifies the entire development workflow.
How do I install UiAutomatorViewer?
UiAutomatorViewer is part of the Android SDK. You don’t need to “install” it separately.
Once you have Android Studio and the Android SDK installed, you can find the uiautomatorviewer.bat
Windows or uiautomatorviewer
macOS/Linux executable in the tools/bin
directory of your Android SDK installation.
What is the resource-id
in UiAutomator?
The resource-id
is a unique identifier assigned to a UI element within an Android application.
It’s often the most reliable way to locate an element in UiAutomator tests because it’s less prone to change than visible text or position.
It typically follows the format package_name:id/element_id
.
Can UiAutomator interact with system UI elements like notifications or settings?
Yes, absolutely.
One of UiAutomator’s main strengths is its ability to interact with any UI element on the device screen, including system UI elements like notifications, quick settings, system dialogs, and the device’s main Settings app.
This makes it ideal for testing multi-app workflows.
How do I handle dynamic elements that appear or disappear in UiAutomator?
To handle dynamic elements, use the Until
class in UiAutomator 2.0. Instead of arbitrary Thread.sleep
calls, Until
allows you to wait for specific conditions to be met, such as an object appearing Until.hasObject
, disappearing Until.gone
, or changing its text Until.textMatches
. This makes your tests more robust and less flaky.
What is the Page Object Model POM in UiAutomator?
The Page Object Model is a design pattern that encourages creating a separate class for each distinct screen or major component of your application.
Each “Page Object” class encapsulates the UI elements locators and the interactions methods available on that screen.
This approach improves test readability, maintainability, and reusability, as UI changes only require updates in the Page Object, not in every test case.
How can I make my UiAutomator tests less flaky?
To reduce flakiness:
- Use
Until
for Smart Waits: AvoidThread.sleep
. - Robust Element Identification: Prioritize
resource-id
, thencontent-desc
, thentext
usetextContains
cautiously, and combine selectors. Avoidindex
and coordinates. - Page Object Model: Improves organization and maintainability, reducing errors from incorrect locators.
- Error Handling: Implement
try-catch
blocks for critical actions. - Screenshots on Failure: Capture visual evidence to understand why a test failed.
- Clean Test State: Ensure each test starts from a known, clean state e.g., launching the app fresh, clearing data.
Can UiAutomator run on real devices and emulators?
Yes, UiAutomator tests can be executed on both physical Android devices connected via USB with USB debugging enabled and Android emulators AVDs. This flexibility allows for comprehensive testing across various device types and Android versions.
How do I integrate UiAutomator tests into a CI/CD pipeline?
Integrating UiAutomator tests into CI/CD involves:
- Setting up a CI agent: Install JDK and Android SDK on the agent.
- Configuring an Android Emulator: Create and start an AVD on the CI machine, or integrate with a cloud device farm e.g., Firebase Test Lab.
- Running Gradle command: Execute
./gradlew connectedAndroidTest
orgradlew.bat connectedAndroidTest
to run the tests. - Collecting Reports: Publish test results e.g., JUnit XML reports generated by Gradle to your CI platform for visualization.
What is UiDevice
in UiAutomator?
UiDevice
is the central object in the UiAutomator framework that represents the device’s current state.
It provides methods to interact with the device as a whole, such as pressing system buttons pressHome
, pressBack
, opening notifications openNotificationShade
, rotating the screen, or executing shell commands.
It’s the entry point for all UiAutomator interactions.
How do I find UI elements using UiObject2
?
UiObject2
is the newer and generally preferred way to interact with UI elements in UiAutomator 2.0. You find elements using By
selectors e.g., By.res
, By.text
, By.desc
, By.clazz
. You then use device.findObjectBy.selector
to get a UiObject2
instance.
For example: UiObject2 loginButton = device.findObjectBy.res"com.myapp:id/login_button".
.
Can UiAutomator simulate multi-touch gestures like pinch-to-zoom?
Yes, UiObject2
provides methods like pinchIn
and pinchOut
to simulate multi-touch pinch gestures for zooming.
It also supports swipe
and drag
for other complex touch interactions.
How do I take a screenshot during a UiAutomator test?
You can take a screenshot using device.takeScreenshotFile path
. It’s a best practice to take screenshots on test failures to aid in debugging, saving them to a location like /sdcard/Download/
on the device, and then pulling them for analysis.
What’s the difference between UiObject
and UiObject2
?
UiObject
older API is immutable.
It represents the element that matched the selector at the time of its creation. If the UI changes, it might become stale.
UiObject2
newer API, part of AndroidX Test is more dynamic.
It automatically re-locates the UI element if the UI changes, making it more resilient to dynamic UIs and offering better performance.
UiObject2
works with By
selectors, while UiObject
uses UiSelector
.
Can UiAutomator test web views within an Android app?
UiAutomator can interact with web views in a limited capacity. It sees the web view as a single UI element e.g., a android.webkit.WebView
class. It cannot directly inspect or interact with individual elements within the web content e.g., specific buttons or text inside the HTML. For web view content, you would typically use a hybrid testing approach, combining UiAutomator for native elements and a framework like Selenium or Appium with WebView contexts for the web content.
Is it possible to run UiAutomator tests in parallel?
Yes, parallel execution of UiAutomator tests is possible but requires careful setup.
You can run tests in parallel across multiple physical devices or emulators connected to the same machine, or distribute them across different CI agents or device farms like Firebase Test Lab. Android’s AndroidJUnitRunner
supports parallel execution on multiple devices.
How do I debug a failed UiAutomator test?
- Examine the Test Report/Stack Trace: This is the first place to look. It pinpoints the line of code that failed and the assertion message.
- Review Logcat: Filter Logcat by your test package or relevant tags
System.out
,TestRunner
,E
for errors. Look for exceptions, crashes, or any unexpected behavior logged by your app or the system. - Screenshots on Failure: If implemented, reviewing screenshots taken at the point of failure can visually reveal what happened.
- Re-run Test Locally: Execute the failing test on your device/emulator in Android Studio and watch it closely to observe the exact interaction sequence and where it deviates from expected behavior.
- Use UiAutomator Viewer: At the point of failure, use UiAutomator Viewer to inspect the current UI hierarchy on the device. This helps verify if the element you’re trying to interact with actually exists with the expected properties.
What are common challenges when using UiAutomator?
Common challenges include:
- Flakiness: Due to timing issues, dynamic UI, or network delays.
- Element Identification: Finding reliable and unique selectors, especially for complex or custom UI components.
- Synchronization Issues: Ensuring tests wait for UI changes to complete before interacting.
- Test Environment Setup: Configuring emulators, handling SDK licenses, and managing device states in CI.
- Debugging Complexity: Diagnosing failures that occur remotely on a device/emulator.
- Maintenance Overhead: Keeping tests updated as the application’s UI evolves.
0.0 out of 5 stars (based on 0 reviews)
There are no reviews yet. Be the first one to write one. |
Amazon.com:
Check Amazon for Android app automation Latest Discussions & Reviews: |
Leave a Reply