当前位置: 首页 > news >正文

Appium+Python 实现移动应用自动化测试:从基础到实战

在移动应用开发中,自动化测试是保障产品质量的关键环节。Appium 作为一款跨平台的移动自动化工具,支持 iOS 和 Android,且能与 Python 等主流语言结合,成为很多开发者的首选。本文将基于实际项目代码,带你掌握 Appium+Python 的核心用法,实现从应用登录到功能循环测试的全流程自动化。

一、环境准备:搭建 Appium 自动化基础

在开始编写代码前,需要先搭建好运行环境,确保设备、工具和依赖都配置到位。

1. 核心工具与依赖安装

  • Appium Server:用于管理自动化会话的服务端,可通过Appium 官网下载桌面版,或通过 npm 安装命令行版(npm install -g appium)。
  • Android SDK:提供 ADB(Android 调试桥)等工具,需配置ANDROID_HOME环境变量,并将platform-tools目录加入 Path(确保adb命令可全局执行)。
  • Python 客户端:安装 Appium Python 库,执行pip install Appium-Python-Client。
  • 测试设备:一台开启 “USB 调试” 的 Android 真机(或模拟器),确保通过 USB 连接电脑后,adb devices命令能识别到设备。

如果不会安装的话可以参考我之前写的博客Appium下载安装配置保姆教程(图文详解)

2. 设备连接检查

在编写代码前,先用 ADB 命令确认设备已正常连接:

# 查看已连接的设备
adb devices

若输出类似1234567890ABCDEF device,说明设备连接成功(device状态表示可用)。

二、核心操作:Appium+Python 基础用法

Appium 的核心是通过客户端代码与 Appium Server 通信,实现对设备的控制。以下是最常用的基础操作,也是自动化脚本的骨架。

1. 初始化 Appium 会话

要控制设备,需先创建一个 Appium 会话(Session),通过配置 “期望能力”(Desired Capabilities)指定设备和应用信息。

from appium import webdriver
from appium.options.android import UiAutomator2Options# 配置期望能力(Desired Capabilities)
CAPABILITIES = {"platformName": "Android",  # 平台(Android/iOS)"deviceName": "1234567890ABCDEF",  # 设备序列号(通过adb devices获取)"appPackage": "com.jlfc.tml",  # 应用包名"appActivity": ".MainActivity",  # 启动Activity"automationName": "UiAutomator2",  # 自动化引擎(Android推荐UiAutomator2)"noReset": True  # 不重置应用数据(避免每次启动都清除缓存)
}# 初始化会话:连接Appium Server(默认地址http://localhost:4723/wd/hub)
options = UiAutomator2Options().load_capabilities(CAPABILITIES)
driver = webdriver.Remote("http://localhost:4723/wd/hub", options=options)
  • platformName:指定测试平台(必须正确,否则无法连接)。
  • appPackage和appActivity:确定要启动的应用及入口(可通过adb命令获取,前文已讲)。
adb shell dumpsys window | findstr "mCurrentFocus"
  • automationName:指定自动化引擎,Android 推荐UiAutomator2(支持最新系统版本)。

2. 元素定位与操作

自动化的核心是 “找到元素并操作”。Appium 支持多种定位方式,常用的有IDXPath文本,以下是实战中最常用的两种:

(1)通过 ID 定位(最稳定)

元素的resource-id是开发时设置的唯一标识,优先用 ID 定位:

from appium.webdriver.common.appiumby import AppiumBy# 定位“管理员用户”按钮(ID为com.jlfc.tml:id/txt_user_admin)
admin_btn = driver.find_element(by=AppiumBy.ID, value="com.jlfc.tml:id/txt_user_admin")
admin_btn.click()  # 点击按钮

(2)通过 XPath 定位(最灵活)

当元素无唯一 ID 时,可用 XPath 结合文本、属性等定位:

# 定位文本为“固件版本升级”的选项
upgrade_item = driver.find_element(by=AppiumBy.XPATH, value="//android.widget.TextView[@text='固件版本升级']"
)
upgrade_item.click()# 定位包含“登录”文本的按钮
login_btn = driver.find_element(by=AppiumBy.XPATH, value="//android.widget.Button[contains(@text, '登录')]"
)

3. 等待机制:避免 “元素未加载” 问题

应用界面加载需要时间,直接定位元素可能导致 “找不到元素” 错误。需使用显式等待,等待元素处于可操作状态后再执行操作:

from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutExceptiondef wait_element_clickable(driver, locator, timeout=10):"""等待元素可点击"""try:# 等待timeout秒,直到元素可点击return WebDriverWait(driver, timeout).until(EC.element_to_be_clickable(locator))except TimeoutException:raise Exception(f"超时未找到可点击元素:{locator}")# 用法:等待“登录按钮”可点击后点击
login_btn_locator = (AppiumBy.ID, "com.jlfc.tml:id/btn_login")
wait_element_clickable(driver, login_btn_locator).click()
  • 显式等待比time.sleep()更高效(无需固定等待时间,元素加载完成后立即执行)。
  • 超时时间根据页面复杂度设置(一般 5-15 秒)。

4. 常用交互操作

除了点击,Appium 还支持输入文本、滑动、返回主页等常用操作:

# 输入文本(如账号密码)
username_input = driver.find_element(by=AppiumBy.ID, value="com.jlfc.tml:id/edit_username")
username_input.send_keys("yy_after")  # 输入账号# 滑动屏幕(上滑,参数:起始x、起始y、结束x、结束y、持续时间)
def swipe_up(driver):size = driver.get_window_size()  # 获取屏幕尺寸driver.swipe(size["width"] * 0.5,  # 起始x(屏幕中间)size["height"] * 0.8,  # 起始y(屏幕下方)size["width"] * 0.5,  # 结束x(屏幕中间)size["height"] * 0.2,  # 结束y(屏幕上方)500  # 滑动持续时间(毫秒))# 返回手机主页(按Home键,keycode=3)
driver.press_keycode(3)

5. 关闭会话

测试结束后,需关闭会话释放资源:

driver.quit()  # 关闭当前会话,释放设备

三、实战案例:实现应用登录与循环测试

基于以上基础,我们可以组合出完整的自动化场景。以下面应用为例,实现 “管理员登录” 和 “固件升级循环测试” 两个核心流程。

1. 管理员登录流程

登录是大多数应用的基础操作,需处理 “应用已打开” 和 “需重新启动应用” 两种场景:

def login_admin(driver):# 检查是否已显示“管理员用户”按钮admin_btn_locator = (AppiumBy.ID, "com.jlfc.tml:id/txt_user_admin")try:# 若已显示,直接点击wait_element_clickable(driver, admin_btn_locator, timeout=2).click()print("已点击管理员用户按钮")except TimeoutException:# 若未显示,返回主页并重启应用driver.press_keycode(3)  # 返回主页time.sleep(2)# 滑动查找应用图标并点击(最多滑3次)max_scrolls = 3for i in range(max_scrolls):try:# 定位应用图标(文本为“唐米力”)app_icon = wait_element_clickable(driver, (AppiumBy.XPATH, '//*[@text="唐米力"]'), timeout=5)app_icon.click()print("已启动应用")time.sleep(5)  # 等待应用启动breakexcept TimeoutException:if i == max_scrolls - 1:raise Exception("未找到应用图标")swipe_up(driver)  # 上滑屏幕print(f"已上滑{i+1}次")# 启动后点击管理员按钮wait_element_clickable(driver, admin_btn_locator).click()# 输入账号密码并登录wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/edit_username")).send_keys("yy")wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/edit_password")).send_keys("123456")wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/btn_login")).click()# 验证登录成功(检查“自动炒菜”文本是否显示)wait_element_clickable(driver, (AppiumBy.XPATH, "//*[@text='自动炒菜']"), timeout=15)print("管理员登录成功")

2. 固件升级循环测试

很多场景需要重复执行某一操作(如多次测试固件升级),可通过循环实现,并加入异常处理确保稳定性:

def run_firmware_upgrade(driver, run_count=10):"""循环执行固件升级测试"""stop_flag = False  # 用于标记是否停止后续测试for i in range(run_count):if stop_flag:print("检测到错误,停止后续升级测试")breaktry:print(f"\n===== 第{i+1}次固件升级 =====")# 检查会话是否有效(避免设备断开)try:driver.current_activity  # 获取当前Activity,验证会话except Exception:raise Exception("会话已失效,需重新初始化")# 进入设置页面wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/img_settings")).click()# 点击“固件版本升级”wait_element_clickable(driver, (AppiumBy.XPATH, "//*[@text='固件版本升级' and @resource-id='android:id/title']")).click()# 点击确认升级wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/btn_confirm")).click()# 等待升级完成(最长360秒)wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/btn_login"),  # 升级后回到登录页timeout=360)print(f"第{i+1}次升级完成,已返回登录页")# 点击登录按钮,准备下一次测试wait_element_clickable(driver, (AppiumBy.ID, "com.jlfc.tml:id/btn_login")).click()except Exception as e:# 捕获异常,标记停止后续测试print(f"第{i+1}次升级失败:{str(e)}")stop_flag = True# 可在此处添加截图功能(见下文)

3. 异常处理与截图

测试出错时,截图能帮助定位问题,可封装一个截图函数:

import os
from datetime import datetimedef take_screenshot(driver, name):"""保存截图到本地"""# 创建截图目录screenshot_dir = "screenshots"if not os.path.exists(screenshot_dir):os.makedirs(screenshot_dir)# 截图文件名(包含时间戳)timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")filename = f"{screenshot_dir}/{name}_{timestamp}.png"# 保存截图driver.save_screenshot(filename)print(f"截图已保存:{filename}")return filename# 用法:在异常时调用
try:# 测试步骤...
except Exception as e:take_screenshot(driver, "upgrade_failure")raise e

四、自动化测试最佳实践

  1. 优先使用稳定的定位方式:ID > XPath(属性组合) > 文本(文本可能随语言变化)。
  2. 合理设置等待时间:避免用time.sleep(),多用显式等待;根据页面加载速度调整超时时间。
  3. 处理会话失效:设备断开、应用崩溃可能导致会话失效,需在关键步骤前检查会话状态(如driver.current_activity)。
  4. 循环测试加中断机制:重复测试时,一旦出现致命错误,立即停止后续执行(如上文的stop_flag),避免无效执行。
  5. 及时清理资源:测试结束后务必调用driver.quit(),释放设备连接,避免影响其他测试。

请添加图片描述

到这里我的分享就结束了,欢迎到评论区探讨交流!!

💖如果觉得有用的话还请点个赞吧 💖

http://www.dtcms.com/a/327021.html

相关文章:

  • STFT、log-mel、MFCC 的区别
  • 梳理一下实现3D显示的途径有哪些?
  • QT(概述、基础函数、界面类、信号和槽)
  • Qt之QMetaEnum的简单使用(含源码和注释)
  • [激光原理与应用-253]:理论 - 几何光学 - 变焦镜头的组成原理及图示解析
  • excel-随笔记
  • 单例模式,动态代理,微服务原理
  • [特殊字符]深度解析 FastMCP:重构MCP应用开发的全维度革命
  • 当机械臂装上「智能大脑」:Deepoc具身智能模型如何重构传统自动化​
  • 力扣经典算法篇-50-单词规律(双哈希结构+正反向求解)
  • 【Golang】pprof 使用介绍:从数据采集到可视化分析
  • windows版本:Prometheus+Grafana(普罗米修斯+格拉法纳)监控 JVM
  • Webpack 介绍与使用的详细介绍
  • ChatGpt 5系列文章1——编码与智能体
  • 地图可视化实践录:显示地理区域图
  • 【Bug经验分享】由jsonObject-TypeReference引发的序列化问题
  • 完整多端口 Nginx Docker部署 + GitLab Runner注册及标签使用指南
  • Table Foundation Models: on knowledge pre-training for tabular learning(每日一文)
  • 安卓主题定制实践:17.45MB轻量级主题引擎技术解析
  • Text Animator for Unity快速上手
  • Milvus入门:开源向量数据库,解锁大模型时代的高效检索
  • 面试八股之从jvm层面深入解析Java中的synchronized关键字
  • 【AI绘画】Stable Diffusion webUI 常用功能使用技巧
  • JVM 内存大对象监控和优化实践
  • AT F-Intervals 题解
  • 【KO】大厂常见问题
  • 局域网远程控制/推流
  • 从裸机到云原生:Linux 操作系统实战进阶的“四维跃迁”
  • 嵌入式调试利器:STM32F429移植letter-shell实战
  • 【第四章:大模型(LLM)】05.LLM实战: 实现GPT2-(7)模型训练与微调