Appium 移动端自动化测试(二):第一个测试脚本与元素定位策略

本篇带你编写第一个 Android 和 iOS 的 Appium 测试脚本,并掌握移动端元素定位方法。

一、第一个 Appium 测试脚本

1.1 Android 测试脚本

from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
import time

def test_android_app():
    """Android 应用自动化测试示例"""

    capabilities = AppiumOptions()
    capabilities.load_capabilities({
        "platformName": "Android",
        "appium:deviceName": "Pixel 6",
        "appium:platformVersion": "14",
        "appium:automationName": "UiAutomator2",
        "appium:app": "/path/to/app.apk",
        "appium:noReset": True,
    })

    driver = webdriver.Remote("http://127.0.0.1:4723", options=capabilities)

    try:
        # 等待应用启动
        time.sleep(3)

        # 输入用户名
        username = driver.find_element(AppiumBy.ID, "com.example.app:id/username")
        username.send_keys("testuser")

        # 输入密码
        password = driver.find_element(AppiumBy.ID, "com.example.app:id/password")
        password.send_keys("123456")

        # 点击登录按钮
        login_btn = driver.find_element(AppiumBy.ID, "com.example.app:id/login_btn")
        login_btn.click()

        # 验证登录成功
        time.sleep(2)
        welcome = driver.find_element(AppiumBy.ID, "com.example.app:id/welcome_text")
        assert "欢迎" in welcome.text
        print("Android 测试通过!")

    finally:
        driver.quit()

1.2 iOS 测试脚本

from appium import webdriver
from appium.options.common.base import AppiumOptions
from appium.webdriver.common.appiumby import AppiumBy
import time

def test_ios_app():
    """iOS 应用自动化测试示例"""

    capabilities = AppiumOptions()
    capabilities.load_capabilities({
        "platformName": "iOS",
        "appium:deviceName": "iPhone 15",
        "appium:platformVersion": "17.2",
        "appium:automationName": "XCUITest",
        "appium:app": "/path/to/app.ipa",
        "appium:noReset": True,
    })

    driver = webdriver.Remote("http://127.0.0.1:4723", options=capabilities)

    try:
        time.sleep(3)

        # iOS 元素定位方式与 Android 类似
        username = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "usernameInput")
        username.send_keys("testuser")

        password = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "passwordInput")
        password.send_keys("123456")

        login_btn = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "loginButton")
        login_btn.click()

        time.sleep(2)
        welcome = driver.find_element(AppiumBy.ACCESSIBILITY_ID, "welcomeText")
        assert "欢迎" in welcome.text
        print("iOS 测试通过!")

    finally:
        driver.quit()

1.3 使用 pytest 组织测试

# conftest.py
import pytest
from appium import webdriver
from appium.options.common.base import AppiumOptions

@pytest.fixture(scope="function")
def android_driver():
    """Android driver fixture"""
    capabilities = AppiumOptions()
    capabilities.load_capabilities({
        "platformName": "Android",
        "appium:deviceName": "Pixel 6",
        "appium:automationName": "UiAutomator2",
        "appium:app": "/path/to/app.apk",
        "appium:noReset": True,
    })

    driver = webdriver.Remote("http://127.0.0.1:4723", options=capabilities)
    driver.implicitly_wait(10)
    yield driver
    driver.quit()

# test_login.py
from appium.webdriver.common.appiumby import AppiumBy

def test_login_success(android_driver):
    """pytest 风格的测试"""
    driver = android_driver

    driver.find_element(AppiumBy.ID, "com.example.app:id/username").send_keys("admin")
    driver.find_element(AppiumBy.ID, "com.example.app:id/password").send_keys("123456")
    driver.find_element(AppiumBy.ID, "com.example.app:id/login_btn").click()

    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC

    welcome = WebDriverWait(driver, 10).until(
        EC.presence_of_element_located((AppiumBy.ID, "com.example.app:id/welcome_text"))
    )
    assert "欢迎" in welcome.text

二、元素定位策略

2.1 移动端定位方法总览

方法 AppiumBy 常量 Android 支持 iOS 支持 推荐度
ID AppiumBy.ID 原生资源 ID Accessibility ID
Accessibility ID AppiumBy.ACCESSIBILITY_ID content-desc accessibilityIdentifier
XPath AppiumBy.XPATH 支持 支持
Class Name AppiumBy.CLASS_NAME UI 组件类名 UI 组件类名
Android UISelector AppiumBy.ANDROID_UIAUTOMATOR 仅 Android 不支持
Android DataMatcher AppiumBy.ANDROID_DATA_MATCHER 仅 Android 不支持
iOS Predicate AppiumBy.IOS_PREDICATE 不支持 仅 iOS
iOS Class Chain AppiumBy.IOS_CLASS_CHAIN 不支持 仅 iOS
CSS Selector AppiumBy.CSS_SELECTOR WebView WebView

2.2 各方法详解

ID 定位

# Android:使用资源 ID(推荐)
driver.find_element(AppiumBy.ID, "com.example.app:id/login_btn")

# iOS:使用 accessibility identifier
driver.find_element(AppiumBy.ID, "loginButton")

Android 开发者注意:在布局 XML 中设置 android:id,Appium 会自动加上包名前缀。

Accessibility ID 定位(推荐)

# Android:对应 content-desc 属性
# XML: android:contentDescription="登录按钮"
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "登录按钮")

# iOS:对应 accessibilityIdentifier
driver.find_element(AppiumBy.ACCESSIBILITY_ID, "loginButton")

最佳实践:Accessibility ID 跨平台通用,优先使用。

XPath 定位

# 基本定位
driver.find_element(AppiumBy.XPATH, "//android.widget.Button[@text='登录']")
driver.find_element(AppiumBy.XPATH, "//XCUIElementTypeButton[@name='Login']")

# 多属性组合
driver.find_element(AppiumBy.XPATH,
    "//android.widget.EditText[@resource-id='com.example:id/username' and @text='']"
)

# 层级定位
driver.find_element(AppiumBy.XPATH,
    "//android.widget.LinearLayout[@resource-id='com.example:id/form']//android.widget.Button"
)

# 模糊匹配
driver.find_element(AppiumBy.XPATH, "//android.widget.Button[contains(@text, '登录')]")

Class Name 定位

# Android
driver.find_element(AppiumBy.CLASS_NAME, "android.widget.EditText")
driver.find_element(AppiumBy.CLASS_NAME, "android.widget.Button")

# iOS
driver.find_element(AppiumBy.CLASS_NAME, "XCUIElementTypeTextField")
driver.find_element(AppiumBy.CLASS_NAME, "XCUIElementTypeButton")

注意:Class Name 通常返回多个元素,建议结合 find_elements 使用。

Android UIAutomator 定位

# 使用 UiSelector(仅 Android)
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
    'new UiSelector().text("登录")'
)

# 组合条件
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
    'new UiSelector().className("android.widget.EditText").instance(0)'
)

# 模糊匹配
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
    'new UiSelector().textContains("登录")'
)

# 可滚动查找
driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR,
    'new UiScrollable(new UiSelector().scrollable(true))' +
    '.scrollIntoView(new UiSelector().text("更多"))'
)

iOS 特有定位

# iOS Predicate(谓词表达式)
driver.find_element(AppiumBy.IOS_PREDICATE,
    "type == 'XCUIElementTypeButton' AND name == 'Login'"
)
driver.find_element(AppiumBy.IOS_PREDICATE,
    "type == 'XCUIElementTypeTextField' AND value == ''"
)

# iOS Class Chain(类链)
driver.find_element(AppiumBy.IOS_CLASS_CHAIN,
    "**/XCUIElementTypeTextField[`value == ''`]"
)
driver.find_element(AppiumBy.IOS_CLASS_CHAIN,
    "**/XCUIElementTypeButton[`name == 'Login'`]"
)

三、元素定位工具

3.1 Appium Inspector

Appium Inspector 是官方提供的 GUI 元素检查工具。

# 安装
npm install -g appium-inspector

# 启动
appium-inspector

使用步骤:

  1. 配置 Remote Path 和 Capabilities
  2. 点击 "Start Session" 连接设备
  3. 选中页面元素查看属性
  4. 右键元素 → Copy → 选择定位方式

3.2 Android:UIAutomatorViewer

# 位于 Android SDK 目录
$ANDROID_HOME/tools/bin/uiautomatorviewer

使用步骤:

  1. 连接设备或启动模拟器
  2. 点击 "Device Screenshot" 获取页面截图
  3. 点击元素查看节点树和属性

3.3 Android:Appium UIAutomator2 内置

# 通过代码获取页面源码
page_source = driver.page_source
with open("page_source.xml", "w", encoding="utf-8") as f:
    f.write(page_source)

3.4 定位策略选择建议

优先级:Accessibility ID > ID > iOS Predicate / Android UIAutomator > XPath

选择原则:
- 跨平台测试 → Accessibility ID
- Android 专属 → ID / UIAutomator
- iOS 专属 → ID / Predicate / Class Chain
- 两者都不满足 → XPath(最灵活但性能最差)

四、总结

场景 推荐方法
跨平台通用 AppiumBy.ACCESSIBILITY_ID
Android 原生 AppiumBy.ID / AppiumBy.ANDROID_UIAUTOMATOR
iOS 原生 AppiumBy.ID / AppiumBy.IOS_PREDICATE
WebView 内容 AppiumBy.CSS_SELECTOR / AppiumBy.XPATH
列表中滚动查找 AppiumBy.ANDROID_UIAUTOMATOR(UiScrollable)

下一篇:常用 Appium API 详解,涵盖点击、输入、滑动手势等操作。

posted @ 2026-04-07 16:06  小小阿狸。  阅读(0)  评论(0)    收藏  举报