杰瑞科技汇

Python如何用UI Automator实现自动化测试?

Of course! Here’s a comprehensive guide to using UI Automator with Python for Android UI testing.

Python如何用UI Automator实现自动化测试?-图1
(图片来源网络,侵删)

Executive Summary

UI Automator is a powerful UI testing framework from Google that allows you to test across multiple apps by targeting UI components. While the official SDK is in Java/Kotlin, you can use it with Python by leveraging uiautomator2, a popular third-party library that acts as a wrapper around the UI Automator 2 framework.

This guide will cover:

  1. What is UI Automator and uiautomator2?
  2. How to Set Up Your Environment (Python, ADB, and the device/emulator).
  3. Installation of uiautomator2.
  4. Core Concepts and Basic Usage (connecting, finding elements, interacting with them).
  5. Practical Code Examples.
  6. Advanced Features (screenshots, screen recordings, installing/uninstalling apps).
  7. Running Tests on a Physical Device vs. Emulator.

What is UI Automator and uiautomator2?

  • UI Automator (The Android Framework): A system-level testing framework provided by Google. It's part of the AndroidX Test library. Its key advantage is that it can interact with any app on the device, not just your own app. It works by scanning the UI hierarchy and matching components based on properties like text, content description, or resource ID.

  • uiautomator2 (The Python Wrapper): This is a Python library created by open-source contributors. It simplifies the process of using UI Automator from Python. It works by:

    Python如何用UI Automator实现自动化测试?-图2
    (图片来源网络,侵删)
    1. Pushing a test server APK (atx-agent) onto your Android device.
    2. Starting an HTTP server on the device that listens for commands from your Python script.
    3. Translating your Python method calls into HTTP requests to this server.
    4. The server then uses the native UI Automator framework to perform the actions on the device.

Think of uiautomator2 as the bridge that lets you speak Python to the Android UI Automator engine.


Prerequisites: Environment Setup

Before you start, you need the following tools installed and configured.

A. Python

Ensure you have Python 3.6+ installed on your machine.

B. Android SDK Platform-Tools (ADB)

ADB (Android Debug Bridge) is essential for communicating with your Android device or emulator.

Python如何用UI Automator实现自动化测试?-图3
(图片来源网络,侵删)
  1. Download: Get it from the official Android Developers site.
  2. Add to PATH: Add the platform-tools directory to your system's PATH environment variable so you can run adb from anywhere.
  3. Verify: Open your terminal/command prompt and run:
    adb version

    You should see the ADB version number.

C. An Android Device or Emulator

You need a target to run your tests on.

  • Physical Device: Enable Developer Options and USB Debugging in the device settings.
  • Emulator: Create an Android Virtual Device (AVD) using Android Studio or the avdmanager command line tool.

D. Verify ADB Connection

Connect your device or start your emulator. In your terminal, run:

adb devices

You should see your device/emulator listed with device next to it.


Installation of uiautomator2

It's highly recommended to install the library in a Python virtual environment.

# Create and activate a virtual environment (optional but recommended)
python -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
# Install the library
pip install --pre uiautomator2

First-Time Setup on the Device

After installing the Python library, you need to prepare your Android device/emulator to work with uiautomator2. This is a one-time setup process per device.

Run the following command in your terminal:

python -m uiautomator2 init

This command will:

  1. Check if your device is connected via ADB.
  2. Install the atx-agent APK (the test server) on your device.
  3. Grant the necessary permissions to the agent.
  4. Print the URL of the device's server, which looks like http://<device_ip>:7912.

Core Concepts and Basic Usage

Let's write some Python code to interact with a device.

A. Connecting to the Device

The primary object you'll work with is Device.

import uiautomator2 as u2
# Connect to the device over USB
# This will use the first device found by 'adb devices'
d = u2.connect()
# Or connect to a specific device using its serial
# d = u2.connect("emulator-5554")
# Or connect via WiFi (once connected via USB, you can get the IP from d.info['wlanip'])
# d = u2.connect("192.168.1.10")
print("Device connected successfully!")
print(d.info) # Prints device information like model, Android version, etc.

B. Finding UI Elements

The Device object (d) has a method called info that gives you the current UI hierarchy. You can also use specific methods to find elements.

The most common way to find elements is using d(resourceId="...") or d(text="...").

Selector Method Description Example
d(resourceId="...") Finds an element by its Android resource ID. d(resourceId="com.android.settings:id/search")
d(text="...") Finds an element by its visible text. d(text="Wi-Fi")
d(description="...") Finds an element by its content description (used for accessibility). d(description="Open navigation drawer")
d(textContains="...") Finds an element whose text contains the given string. d(textContains="search")
d(textMatches="...") Finds an element whose text matches the given regex. d(textMatches=r"Settings.*")
d(className="...") Finds an element by its class name (e.g., android.widget.Button). d(className="android.widget.Button")

C. Interacting with Elements

Once you have an element (or a list of elements), you can perform actions on it.

# Assuming you are on the Android Home Screen
# 1. Find and click an app by its text
print("Opening 'Settings' app...")
d(text="Settings").click()
# 2. Find a text field and enter text
print("Searching for 'Bluetooth'...")
# The resourceId might be different on your device
search_bar = d(resourceId="com.android.settings:id/search")
search_bar.set_text("Bluetooth") # Use .click() to focus first if needed
# 3. Find a button and click it
# The text might be 'SEARCH' or a magnifying glass icon
d(text="SEARCH").click()
# 4. Wait for an element to appear and then click it
# This is more robust than a direct click
print("Clicking on 'Bluetooth' option...")
d(text="Bluetooth").wait.exists(timeout=5000) # Wait for 5 seconds
d(text="Bluetooth").click()

Practical Code Example: A Simple Test Script

Here is a complete script that opens the Settings app, searches for "Battery", and verifies that the "Battery" option is present.

import uiautomator2 as u2
import time
def test_battery_settings():
    """
    A simple test to navigate to Battery settings in the Android Settings app.
    """
    try:
        # 1. Connect to the device
        print("Connecting to device...")
        d = u2.connect()
        print(f"Connected to: {d.info['productName']}")
        # 2. Launch the Settings app
        print("Launching Settings app...")
        d.app_start("com.android.settings")
        time.sleep(2) # Wait for app to launch
        # 3. Search for "Battery"
        print("Searching for 'Battery'...")
        # Using a more robust selector that looks for a search icon
        search_icon = d(resourceId="com.android.settings:id/search", className="android.widget.ImageButton")
        if not search_icon.exists:
            print("Could not find search icon. Aborting.")
            return
        search_icon.click()
        time.sleep(1)
        # Enter text into the search field
        search_field = d(resourceId="android:id/search_src_text")
        search_field.set_text("battery")
        time.sleep(2) # Wait for search results to load
        # 4. Verify and click the "Battery" option
        print("Verifying 'Battery' option exists...")
        battery_option = d(text="Battery")
        if battery_option.exists:
            print("Found 'Battery' option. Clicking it.")
            battery_option.click()
            time.sleep(2)
            print("Successfully navigated to Battery settings.")
        else:
            print("ERROR: 'Battery' option not found after search.")
            return
        # 5. Take a screenshot for proof
        d.screenshot("battery_settings.png")
        print("Screenshot saved as 'battery_settings.png'")
    except Exception as e:
        print(f"An error occurred: {e}")
    finally:
        # 6. Go back to home screen
        print("Pressing home button.")
        d.press("home")
if __name__ == "__main__":
    test_battery_settings()

Advanced Features

uiautomator2 offers much more than just clicking and typing.

A. Taking Screenshots

d.screenshot("my_screenshot.png")

B. Recording the Screen

# Start recording
d.screenrecord.start("my_recording.mp4")
# ... perform your test actions ...
# Stop recording (the file will be saved on your device)
d.screenrecord.stop()
# Pull the file from the device to your computer
d.pull("/sdcard/my_recording.mp4", ".")

C. Installing and Uninstalling Apps

# Install an APK from your local machine
d.install("path/to/your/app.apk")
# Uninstall an app
d.app_uninstall("com.example.your.app")

D. Handling Toast Messages

Toast messages are small pop-ups that appear temporarily.

# Wait for a toast with specific text to appear
d.toast.show("Successfully saved", 1) # Shows a toast for testing
assert d.toast.get_message(5, default="") == "Successfully saved"

E. Gestures (Swipe, Drag, etc.)

# Swipe from one point to another
d.swipe(100, 500, 100, 100, steps=10) # From (x1,y1) to (x2,y2) in 10 steps
# Swipe on an element
d(text="Settings").swipe("up")
# Drag an element
d.drag(100, 200, 300, 400, 0.5) # From (x1,y1) to (x2,y2) over 0.5 seconds

Running on a Physical Device vs. Emulator

Feature Physical Device Emulator
Setup Enable Developer Options & USB Debugging. Create an AVD.
Connection Usually via USB (adb devices). Via USB or Wi-Fi.
Performance Can be faster or slower depending on the device. Can be slow, especially on emulators without hardware acceleration.
Access Has a real camera, sensors, etc. Simulates sensors and can use a webcam for camera.
First-Time Setup python -m uiautomator2 init python -m uiautomator2 init
Wi-Fi Connection Possible after initial USB setup. Use d.wlan_ip to get the IP address. Possible after initial USB setup.

Conclusion and Best Practices

  • Use Waits: Always use .wait.exists(timeout=...) or time.sleep() to make your tests stable and wait for elements to appear.
  • Be Specific with Selectors: Prefer resourceId over text when possible, as text can change with locale. textContains is a good fallback.
  • Organize Tests: For larger projects, use a testing framework like pytest to structure your tests, set up fixtures for connecting to the device, and generate reports.
  • Clean Up: Use try...finally blocks to ensure your app is closed or the device is returned to a known state after a test, even if it fails.
分享:
扫描分享到社交APP
上一篇
下一篇