Appium是一款开源的跨平台移动应用自动化测试框架,允许你使用相同的 API 为 iOS、Android甚至Windows平台编写原生、混合及移动Web应用的测试脚本。主要优势是跨平台能力、多语言支持(如 Python, Java, JavaScript 等)以及对原生应用的无需修改就可以进行测试。
主要架构和工作原理
要精通 Appium,首先需理解Client/Server架构和工作流程。
架构组成
Appium Server:运行在电脑上的 HTTP 服务器,负责接收客户端脚本的指令并转发给移动设备。
客户端脚本:你使用 Appium 客户端库(如 Python 的 Appium-Python-Client)编写的测试代码。
设备/模拟器:安装有被测应用的实体设备或模拟器。Appium 通过特定驱动和设备交互。
通信流程
脚本(Client)通过WebDriver协议向Appium Server发送HTTP请求(如"点击"指令)。
Appium Server接收到请求后,会将转发给设备上对应的驱动,如Android的UiAutomator2或iOS的XCUITest。
设备驱动最终在设备上执行相应的自动化操作,并将结果沿原路返回给你的脚本。
设计思路
Appium按照四大设计思路:
你不需要为了自动化而重新编译或修改你的应用。
你不应被限制在某种特定的语言或框架中来编写和运行测试。
不应该为移动端自动化去重新造一套轮子(即 API)。
移动自动化测试框架是开源的。
环境搭建和配置
基础环境准备
Node.js:Appium Server基于Node.js运行,因此需要先安装它。
Java JDK:Android自动化需要Jav 环境。
Android SDK:用于连接和管理 Android 设备,提供adb等主要工具。
(对于 iOS)Xcode:在macOS上进行 iOS 自动化测试必备。
安装 Appium Server
通过NPM安装命令行版本的 Appium:npm install -g appium。
此外,也可以选择安装带有图形界面的Appium Desktop,它内置了Serve 和用于定位元素的Inspector工具。
安装驱动和客户端库
驱动安装:Appium通过驱动和设备交互。对于Android,强烈推荐安装UiAutomator2驱动:appium driver install uiautomator2。对于 iOS,则需要XCUITest驱动。
客户端库安装:根据你选择的编程语言安装对应的客户端库。例如,使用 Python 则运行:pip install Appium-Python-Client。
配置设备连接
确保你的设备可以通过 adb(Android)或 WebDriverAgent(iOS)正常连接。对于模拟器是否已启动。可以使用adb devices命令来验证Android设备是否被正确识别。
Desired Capabilities详解
Desired Capabilities是一个JSON对象,在初始化WebDriver会话时发送给Appium Server,用来告知Server本次测试的设备和应用配置。
以下是一些主要配置项
platformName:操作系统平台,如 "Android" 或 "iOS"。必填项。
platformVersion:设备系统的版本号,如 "11.4"。
deviceName:使用的设备名称,如 "Android Emulator" 或 "iPhone 6s"。必填项。
appPackage:待测应用的包名,如 "com.example.app"。
appActivity:待测应用的启动 Activity,如 ".MainActivity"。
automationName:指定自动化驱动引擎,如 "UiAutomator2"(Android)或 "XCUITest"(iOS)。
noReset:设为 true 可在会话间保留应用数据(如登录状态),避免重复重置。
unicodeKeyboard:设为 true 可启用 Unicode 输入法,方便输入非英文字符。
示例代码:
python
from appium import webdriver
desired_caps = {
"platformName": "Android",
"deviceName": "Android Emulator",
"appPackage": "com.android.calculator2",
"appActivity": ".Calculator",
"automationName": "UiAutomator2",
"noReset": True
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
注意:在实际脚本中,appPackage和appActivity可以通过检查APK文件或使用adb命令获取。
元素定位交互
自动化测试的主要是找到界面元素并和之交互。
元素定位
以下是Appium中常用的元素定位方法,建议优先使用Accessibility ID和ID,因为它们通常更稳定。
Accessibility ID:driver.find_element_by_accessibility_id("content-desc")
//对应元素的 content-desc (Android) 或 accessibilityIdentifier (iOS)。为元素添加可访问性标识。
ID:driver.find_element_by_id("com.taobao.taobao:id/tv_scan_text")
//对应元素的 resource-id 属性 (Android)。
XPath:driver.find_element_by_xpath("//*[@text='扫一扫']")
//功能强大但性能较差,应作为最后手段。谨慎使用,表达式可能随UI微小改动而失效。
UIAutomator (Android):driver.find_element_by_android_uiautomator('new UiSelector().text("text文本")')
//Android 专属,功能强大且速度快。支持文本、类名、滚动查找等。
元素交互操作
定位到元素后,可以模拟各种用户操作:
点击:element.click()
输入文本:element.send_keys("your text")
清除文本:element.clear()
手势操作
Appium 支持复杂的手势操作,如滑动、长按、拖拽等。你可以使用TouchAction或W3C Actions来实现。如,在 Android 中,可以使用UiAutomator的滚动查找功能来滑动到指定元素:
python
driver.find_element_by_android_uiautomator(
'new UiScrollable(new UiSelector().scrollable(true).instance(0)).'
'scrollIntoView(new UiSelector().text("目标文本").instance(0));'
).click()
等待机制:用来提升脚本稳定性
动态加载的界面元素是自动化测试的主要难点,正确的等待脚本很重要。
隐式等待
设置一个全局的超时时间,在查找元素时,如果元素没有立即出现,WebDriver会轮询查找直到超时。
python
driver.implicitly_wait(10) # 单位:秒
只需在创建 Driver 后设置一次即可。
显式等待
这是更推荐、更精确的等待方式。它针对某个特定元素设置等待条件,在指定时间内根据条件进行轮询。
python
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
# 等待最多10秒,直到元素可被点击
element = WebDriverWait(driver, 10).until(
EC.element_to_be_clickable((By.ID, "com.example:id/button"))
)
element.click()
显式等待可以等待元素处于特定状态,如 可点击、可见、存在 等,这比简单的"存在"检查要可靠得多。
示例加技巧
完整实战:Android计算器自动化
下面是一个模拟用户在计算器上执行 "1+2=3" 操作的完整脚本:
python
from appium import webdriver
from appium.webdriver.common.appiumby import AppiumBy # 推荐使用新的 By 策略
desired_caps = {
"platformName": "Android",
"deviceName": "Android Emulator",
"appPackage": "com.android.calculator2",
"appActivity": ".Calculator",
"automationName": "UiAutomator2"
}
driver = webdriver.Remote("http://localhost:4723/wd/hub", desired_caps)
try:
# 使用新的定位符 (AppiumBy)
driver.find_element(by=AppiumBy.ID, value="com.android.calculator2:id/digit_1").click()
driver.find_element(by=AppiumBy.ID, value="com.android.calculator2:id/op_add").click()
driver.find_element(by=AppiumBy.ID, value="com.android.calculator2:id/digit_2").click()
driver.find_element(by=AppiumBy.ID, value="com.android.calculator2:id/eq").click()
result = driver.find_element(by=AppiumBy.ID, value="com.android.calculator2:id/result").text
print(f"计算结果:{result}") # 预期输出:3
finally:
driver.quit() # 确保无论发生什么,最后都会退出驱动
技巧方面
使用 Page Object Model (POM):将页面元素定位和操作封装在单独的类中,使测试逻辑和页面细节分离。
利用 Appium Inspector:这是一个类似Selenium IDE的工具,可以录制操作、查看应用层次结构并生成元素定位代码。
参数化和数据驱动:将测试数据(如用户名、密码)从脚本中分离出来,通过外部文件(如 CSV、JSON)读取,使得一套脚本可以覆盖多种测试场景。
跨应用交互:Appium支持在多个应用间切换,例如,可以从通讯录应用切换到短信应用,实现复杂的跨应用流程测试。
常见故障问题排查
会话启动失败:首先检查Desired Capabilities是否填写正确,特别是appPackage和appActivity。保证Appium Server已启动(默认端口 4723)。
元素找不到:
确认定位表达式是否正确。使用 Appium Inspector 复核。
添加强制的 time.sleep() 临时等待,判断是否是因应用响应慢导致(长期解决方案应是显式等待)。
检查元素是否在 WebView 中,这需要特殊的上下文切换。
脚本不稳定:
避免使用 time.sleep(),改用显式等待。
减少对 XPath 的依赖,尤是复杂的表达式。
在主要操作前后添加截图功能,便于失败时分析。