Of course! Let's dive deep into using UIAutomator with Python. This is a powerful combination for Android UI testing.

What is UIAutomator?
UIAutomator is a UI testing framework for Android. It allows you to test user interactions and UI components across multiple apps and on different Android platforms. It's part of the Android SDK and is designed to be more robust than the older Instrumentation framework because it can interact with any app, not just the one under test.
Key Features:
- Cross-App: You can write tests that interact with system dialogs (like "Allow permissions" or "Select Wi-Fi network") and other apps.
- View Hierarchy: It inspects the current view hierarchy of the device to find UI elements.
- Rich API: Provides a comprehensive API to find elements (by text, resource ID, content description, etc.) and perform actions (click, swipe, setText, etc.).
- Hardware Buttons: Can simulate hardware button presses (Home, Back, Menu, etc.).
How to Use UIAutomator with Python
You don't use UIAutomator directly with Python. Instead, you use it through an Android testing framework that runs on the device and communicates with your Python script. The most common and recommended approach is using Google's uiautomator2 library.
uiautomator2 is a Python library that acts as a bridge. It installs a test server on your Android device, which then exposes a REST API. Your Python script sends commands to this API to control the device.

Step-by-Step Guide: Setting Up and Writing a Test
Step 1: Prerequisites
- Python 3: Make sure you have Python 3 installed on your machine.
- Android Device or Emulator: You need an Android device (with USB debugging enabled) or an Android Emulator (via Android Studio or AVD Manager).
- Android SDK Platform-Tools: This includes
adb(Android Debug Bridge). Make sureadbis in your system's PATH and can detect your device/emulator.- Verify by running
adb devicesin your terminal. You should see your device listed.
- Verify by running
Step 2: Install the Python Library (uiautomator2)
Open your terminal or command prompt and install the library using pip:
pip install --pre uiautomator2
The --pre flag is recommended to get the latest pre-release version, which often has better device compatibility.
Step 3: Initialize the Device
This is a crucial step. You need to run a command that will install the uiautomator2 test server onto your device.
python -m uiautomator2 init
This command will:

- Check if your device is connected via
adb. - Push the necessary APKs to your device.
- Grant the required permissions.
- Start the server on the device.
You should see output indicating success.
Step 4: Write Your First Python Test Script
Now, let's write a simple script to open the "Settings" app and click on "About phone".
# test_settings.py
import uiautomator2 as u2
# Connect to the device
# If you have only one device, you can just use:
d = u2.connect()
# If you have multiple devices, connect by serial:
# d = u2.connect("YOUR_DEVICE_SERIAL")
print("Device connected. Current screen:", d.info)
# 1. Open the Settings app
print("Opening Settings app...")
d.app_start("com.android.settings")
d.wait.gone("com.android.settings:id/search_box") # Wait for the app to load
# 2. Find the "About phone" element and click it
# We'll use the UIAutomator2 Inspector to find the best selector.
print("Finding and clicking 'About phone'...")
about_phone_element = d(resourceId="com.android.settings:id/title", text="About phone")
about_phone_element.click()
# 3. Verify that we are on the "About phone" screen
# We can check for a specific element on this screen.
print("Verifying we are on the 'About phone' screen...")
assert d(resourceId="com.android.settings:id/summary_text").exists
print("Test passed successfully!")
Step 5: Run the Script
Execute the script from your terminal:
python test_settings.py
You should see your device/emulator automatically open the Settings app, navigate to "About phone", and your script will print its progress.
Finding UI Elements (The Most Important Part)
The key to writing effective UIAutomator tests is finding the right elements. Here are the common ways to find them, in order of preference (most reliable first):
Resource ID (Recommended)
This is the most stable way to find elements, as it's unlikely to change unless the app is updated.
# Find an element by its resource ID
element = d(resourceId="com.android.settings:id/search_box")
# Check if it exists before interacting
if element.exists:
element.click()
Text
The visible text on an element. Good for buttons and labels.
# Find an element by its visible text element = d(text="About phone") element.click() # For partial text matching element = d(textContains="phone")
Content Description
The text read by screen readers for accessibility. Useful for icons or elements without visible text.
# Find an element by its content description element = d(description="Search")
UI Hierarchy and Class Name
The class name of the view (e.g., android.widget.TextView, android.widget.Button). This is often the least reliable.
# Find a button by its class name button = d(className="android.widget.Button")
Combining Selectors
You can combine attributes to make your selectors more specific and robust.
# Find a TextView with a specific resource ID AND text element = d(resourceId="com.android.settings:id/title", text="About phone")
Pro Tip: Use the UIAutomator2 Inspector
Finding resource IDs and other attributes manually is difficult. The uiautomator2 library comes with a fantastic web-based inspector.
- Start the Inspector: Run this command in your terminal:
python -m uiautomator2
- Open in Browser: It will print a URL, usually
http://localhost:7979. Open this in your web browser. - Inspect: You will see a live view of your device's screen. You can tap on any element, and the inspector will show you its attributes (resource ID, text, class name, etc.), making it incredibly easy to build your selectors.
Common Actions and Interactions
Once you have an element, you can perform various actions on it.
# Get an element
search_box = d(resourceId="com.android.settings:id/search_box")
# Click
search_box.click()
# Long Click
search_box.long_click()
# Set Text (for EditText fields)
name_field = d(resourceId="com.example.app:id/edit_name")
name_field.set_text("John Doe")
# Get Text
welcome_text = d(text="Welcome!")
print("The welcome text is:", welcome_text.get_text())
# Check if an element exists
if d(text="Save").exists:
print("Save button is visible.")
# Wait for an element to appear or disappear
# d.wait.exists(element, timeout=10000) # Wait up to 10 seconds for element to appear
d.wait.gone("com.android.settings:id/search_box") # Wait until element is gone
Handling Scrolling and Lists
For lists or scrollable views, you can use the scroll method.
# Scroll to the end of a list d(scrollable=True).scroll.toEnd() # Scroll to a specific element d(scrollable=True).scroll.to(text="Last Item") # Scroll forward (down) or backward (up) d(scrollable=True).scroll.forward() d(scrollable=True).scroll.backward()
Advanced: Running Tests with pytest
For a more structured and powerful testing setup, you can integrate uiautomator2 with pytest.
-
Install pytest:
pip install pytest
-
Create a
conftest.pyfile: This file will handle the device connection setup and teardown for all your tests.# conftest.py import pytest import uiautomator2 as u2 @pytest.fixture(scope="session") def device(): """Fixture to connect to the device once for the entire test session.""" d = u2.connect() yield d # Teardown: close the app after all tests are done d.app_stop("com.android.settings") -
Write your test file using the fixture:
# test_settings_pytest.py import pytest def test_open_settings_and_navigate(device): """Opens settings, navigates to About phone, and verifies.""" print("Opening Settings app...") device.app_start("com.android.settings") device.wait.gone("com.android.settings:id/search_box") print("Finding and clicking 'About phone'...") about_phone_element = device(resourceId="com.android.settings:id/title", text="About phone") about_phone_element.click() print("Verifying we are on the 'About phone' screen...") assert device(resourceId="com.android.settings:id/summary_text").exists print("Test passed successfully!") -
Run your tests:
pytest
pytestwill automatically discover thetest_*.pyfiles and the fixtures inconftest.py.
Comparison: UIAutomator vs. Espresso
| Feature | UIAutomator (via uiautomator2) |
Espresso |
|---|---|---|
| Scope | Cross-App. Can test system dialogs and any app. | Intra-App. Primarily for testing the app under test. |
| Speed | Slower. Communicates over a network/adb bridge. | Much Faster. Runs directly on the UI thread. |
| Dependencies | Requires a separate test server on the device. | Part of the Android Testing Support Library. Integrated into the app. |
| Use Case | Integration & System Testing. E2E tests that mimic a real user, including interactions with the OS. | Unit & Integration Testing. Testing the UI of your specific app in a controlled environment. |
Rule of Thumb:
- Use Espresso for fast, reliable, and isolated UI tests of your own app.
- Use UIAutomator (
uiautomator2) for end-to-end tests that need to interact with system components or multiple apps.
