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
使用步骤:
- 配置 Remote Path 和 Capabilities
- 点击 "Start Session" 连接设备
- 选中页面元素查看属性
- 右键元素 → Copy → 选择定位方式
3.2 Android:UIAutomatorViewer
# 位于 Android SDK 目录
$ANDROID_HOME/tools/bin/uiautomatorviewer
使用步骤:
- 连接设备或启动模拟器
- 点击 "Device Screenshot" 获取页面截图
- 点击元素查看节点树和属性
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 详解,涵盖点击、输入、滑动手势等操作。

浙公网安备 33010602011771号