尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Python+Appium 2移动自动化测试:从环境搭建到脚本实战

Python+Appium 2移动自动化测试:从环境搭建到脚本实战 1. 项目概述为什么是PythonAppium如果你正在为移动应用无论是Android还是iOS的回归测试、兼容性测试或者日常的冒烟测试感到头疼每次版本更新都要手动点点点那PythonAppium这套组合拳绝对是你工具箱里不可或缺的利器。我这些年带过不少测试团队从零开始搭建自动化框架Appium几乎是绕不开的选择而Python以其简洁的语法和丰富的生态让它俩成了黄金搭档。简单来说Appium是一个开源的、跨平台的移动应用自动化测试框架。它的核心魅力在于“一次编写到处运行”——你用同一套测试脚本理论上可以测试Android和iOS应用。而Python作为脚本语言里的“瑞士军刀”写起测试用例来又快又清晰特别适合测试工程师快速上手和构建复杂的测试逻辑。市面上那些所谓的“AI自动化测试”或者“自动化测试平台”底层很多也是基于这些开源技术做的封装。所以直接掌握这套原生组合不仅能解决眼前的问题更能让你理解自动化测试的底层逻辑未来无论面对什么工具都能游刃有余。这篇文章我会以一个从业超过十年的老测试的身份带你从零开始手把手拆解如何用Python和Appium搭建一个可用的、健壮的自动化测试环境并完成一个完整的测试用例。我会重点讲清楚每个步骤“为什么”要这么做以及我在实际项目中踩过的那些“坑”确保你拿到的是能直接上手的“干货”而不是一堆零散的官方文档翻译。2. 环境搭建与配置避坑指南环境搭建是劝退新手的第一个门槛网上教程很多但往往忽略了版本兼容性和环境变量这些魔鬼细节。我会以Windows/macOS双平台为例把每一步的原理和注意事项讲透。2.1 Python环境别只盯着安装包很多新手卡在第一步Python安装。他们从官网下载了安装包一路下一步然后在命令行里输入python发现要么提示“不是内部命令”要么调出来的是系统自带的旧版本。核心原因在于环境变量PATH。安装程序通常有个“Add Python to PATH”的选项一定要勾选。如果忘了勾选或者安装后依然不行就需要手动配置。对于Windows用户右键点击“此电脑” - “属性” - “高级系统设置” - “环境变量”。在“系统变量”或“用户变量”中找到Path变量点击“编辑”。添加两条路径具体路径根据你的Python安装位置调整通常类似C:\Users\你的用户名\AppData\Local\Programs\Python\Python311\(Python解释器主目录)C:\Users\你的用户名\AppData\Local\Programs\Python\Python311\Scripts\(pip等工具目录)打开新的命令行窗口输入python --version和pip --version验证。对于macOS/Linux用户 通常更推荐使用Homebrew来安装和管理Python能避免很多权限和路径问题。安装Homebrew后只需执行brew install python即可。系统会自动处理好路径。注意强烈建议使用Python 3.7及以上版本并且避免使用中文用户名路径安装Python某些依赖库在包含中文的路径下可能会编译失败。虚拟环境是专业操作的起点永远不要直接在系统Python环境里安装项目依赖。使用venv创建隔离环境是必须的。# 在你的项目目录下 python -m venv venv # 激活虚拟环境 # Windows: venv\Scripts\activate # macOS/Linux: source venv/bin/activate激活后命令行提示符前会出现(venv)字样。之后所有pip install操作都只影响这个虚拟环境项目迁移和依赖管理会清晰无数倍。2.2 Node.js与Appium 2的安装逻辑Appium 2 是一个巨大的架构改进。Appium 1.x 是一个巨大的单体包而 Appium 2 变成了一个核心驱动appium加各种插件driver,plugin的模式。这带来了更好的灵活性和可维护性但安装步骤也稍有变化。首先需要安装Node.js因为Appium是基于Node.js运行的。去Node.js官网下载LTS长期支持版本安装即可。安装后在命令行用node -v和npm -v检查。然后安装Appium 2npm install -g appium安装完成后用appium -v检查版本。你可能会看到类似3.5.2这样的版本号这是Appium 2的版本系列。最关键的一步安装驱动Driver。Appium 2 核心本身不包含任何设备驱动你需要按需安装。对于Android测试必须安装uiautomator2驱动这是目前Android主流和稳定的选择对于iOS测试则需要安装xcuitest驱动。# 安装Android驱动 appium driver install uiautomator2 # 安装iOS驱动如果在macOS上 appium driver install xcuitest你可以通过appium driver list来查看已安装的驱动。这一步是很多新手运行脚本时报“No driver found”错误的根源。2.3 客户端库与IDE准备安装Python客户端库在激活的虚拟环境中安装Appium的Python客户端。pip install Appium-Python-Client请注意Appium 2 对应的是Appium-Python-Client的 2.x 或更高版本它与Selenium 4兼容。所以通常你会同时安装pip install Appium-Python-Client selenium版本兼容性很重要老教程可能让你装旧版本会导致新特性无法使用。IDE的选择VS Code是当前非常流行的选择轻量且插件丰富。你需要安装Python扩展和Pylance。配置Python解释器路径指向你的虚拟环境中的python.exeWindows或pythonmacOS即可。PyCharm是另一个强大的专业IDE对Python项目管理和调试支持更完善社区版就足够测试开发使用。根据个人习惯选择即可。2.4 移动端环境准备以Android为例开启开发者选项与USB调试在手机“设置”-“关于手机”里连续点击“版本号”7次开启开发者模式。然后在开发者选项中开启“USB调试”。安装Android SDK Platform-Tools这不是完整的Android Studio而是包含adbAndroid调试桥等关键工具的精简包。去Android开发者官网下载解压后将其platform-tools文件夹路径添加到系统的PATH环境变量中。连接电脑用USB线连接手机在命令行输入adb devices。如果看到设备序列号并显示device说明连接成功。如果显示unauthorized需要在手机弹出的“允许USB调试”对话框中点击确认。至此一个完整的PythonAppium 2自动化测试基础环境就搭建好了。这个过程看似步骤繁多但每一步都有其必要性理解后就能举一反三。3. 核心概念与Desired Capabilities解析环境好了我们来聊聊写脚本前必须吃透的核心——Desired Capabilities。你可以把它理解成发给Appium服务器的“一份订单”告诉它“嗨我需要你这样一台设备打开这个应用用这种方式来测试。”3.1 Desired Capabilities是什么它本质上是一个JSON对象在Python里我们用字典dict来表示。里面定义了自动化会话的所有必需参数。没有它Appium就不知道你要测什么、怎么测。一个最基础的Android配置示例from appium import webdriver desired_caps { “platformName”: “Android”, # 平台必须是Android或iOS “platformVersion”: “13”, # 手机系统版本尽量准确 “deviceName”: “Pixel_5”, # 设备名自定义用于日志标识 “appPackage”: “com.example.myapp”, # 被测App的包名 “appActivity”: “.MainActivity”, # 被测App的启动Activity名 “automationName”: “UiAutomator2”, # 自动化引擎必须和安装的driver对应 “noReset”: True, # 是否在会话开始前重置App状态如不清缓存 “unicodeKeyboard”: True, # 启用Unicode键盘支持输入中文等 “resetKeyboard”: True, # 测试结束后重置键盘为原始状态 }每一对键值都有其特定作用。platformName,deviceName,automationName是必填项。appPackage和appActivity用于指定被测应用。实操心得deviceName并不需要和手机真实型号完全一致它只是一个逻辑名称。但platformVersion尽量写对某些控件定位方式可能因系统版本而异。获取包名和Activity最准确的方法是用adb命令先打开你的App然后执行adb shell dumpsys window | findstr mCurrentFocusWindows或adb shell dumpsys window | grep mCurrentFocusmacOS/Linux。3.2 关键Capability参数深度解读automationName这是Appium 2里至关重要的配置。你必须指定一个已安装的驱动名如UiAutomator2Android或XCUITestiOS。如果没装或写错Appium服务器会直接报错。noReset和fullResetnoReset: True不重置应用数据。适合测试连续场景比如你不想每次测试都重新登录。fullReset: True完整重置。会在会话开始前卸载应用结束后再安装。非常干净但耗时。两者都设为False默认每次会话后会清除应用数据但不会卸载。这是最常用的折中方案。newCommandTimeout命令超时时间秒。如果Appium服务器在这段时间内没收到任何新命令会自动结束会话。对于调试或复杂操作可以设大一点比如600。udid当电脑连接了多台设备时必须用这个参数指定具体哪台设备。通过adb devices命令可以获取设备的UDID。理解并合理配置这些Capabilities是写出稳定脚本的基础。很多“脚本跑着跑着就断了”或者“环境不对”的问题根源都在这里。4. 第一个自动化测试脚本实战理论说得再多不如动手写一个。我们来创建一个完整的测试脚本目标是打开手机上的“设置”应用因为它每个手机都有点击“关于手机”选项。4.1 脚本结构与启动会话首先我们导入必要的模块配置Capabilities并初始化驱动。from appium import webdriver from appium.webdriver.common.appiumby import AppiumBy # 推荐使用AppiumBy进行元素定位 import time # 1. 定义Desired Capabilities desired_caps { “platformName”: “Android”, “platformVersion”: “13”, # 请修改为你的手机系统版本 “deviceName”: “Android Emulator”, # 可以是任意名称 “automationName”: “UiAutomator2”, “appPackage”: “com.android.settings”, # 系统设置的应用包名 “appActivity”: “.Settings”, # 系统设置的主Activity “noReset”: True, # 避免每次重置设置 “newCommandTimeout”: 300, } # 2. 指定Appium服务器地址并创建驱动实例 # 默认情况下Appium服务器运行在本地的4723端口 driver webdriver.Remote(‘http://localhost:4723‘, desired_caps) # 等待几秒让应用完全启动 time.sleep(3)关键点webdriver.Remote是建立连接的核心。它告诉Python客户端去连接运行在http://localhost:4723的Appium服务并把我们的“订单”desired_caps发过去。Appium服务会根据这个“订单”去操作手机。4.2 元素定位与交互操作Appium继承了Selenium的定位策略并增加了一些移动端特有的方式。最常用的是通过“资源ID”、“XPath”、“文本”和“无障碍功能Accessibility ID”来定位。我们先找到“关于手机”这个条目并点击。不同手机设置菜单的布局可能略有不同这里以原生Android为例。# 方法1通过文本内容定位如果元素有唯一的文本 try: about_phone driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().text(“关于手机”)‘) about_phone.click() except: # 方法2如果文本不唯一或被翻译可以尝试用XPath # 这是一个示例XPath实际需要根据你的手机UI调整 about_phone driver.find_element(AppiumBy.XPATH, ‘//android.widget.TextView[text“关于手机”]‘) about_phone.click() time.sleep(2) # 等待页面跳转解释一下AppiumBy.ANDROID_UIAUTOMATOR是Android特有的定位方式使用UiAutomator的APIUiSelector().text()是其中通过文本查找的方法。AppiumBy.XPATH是更强大但也更复杂的定位方式可以遍历整个页面元素树。上面的XPath意思是查找一个TextView控件且其text属性等于“关于手机”。所有操作后加一个短暂的sleep是个好习惯给页面加载留出时间但这不是最佳实践后面我们会讲更优雅的“等待”。4.3 获取页面信息与断言点击进入“关于手机”后我们可以获取一些文本来验证是否成功。# 获取页面上的所有文本内容用于调试或查找关键信息 page_source driver.page_source # 在实际测试中我们更倾向于定位特定元素进行断言 # 假设我们想验证“型号”这一行信息存在 # 先找到“型号”标签再找到它相邻的值这需要具体分析页面结构这里仅为示例逻辑 try: model_label driver.find_element(AppiumBy.XPATH, ‘//*[contains(text, “型号”)]‘) print(f“找到设备型号标签: {model_label.text}“) # 更复杂的操作可以是获取其兄弟节点的文本作为型号值 except Exception as e: print(f“未找到型号信息: {e}“) # 一个简单的断言示例使用Python内置的assert # 假设我们成功进入了关于手机页面页面标题应该包含‘关于’ title_element driver.find_element(AppiumBy.CLASS_NAME, ‘android.widget.TextView‘) assert ‘关于‘ in title_element.text, “未成功进入关于手机页面” print(“测试步骤进入‘关于手机’页面成功”)4.4 会话清理与退出测试结束后必须妥善关闭会话释放手机资源。# 等待几秒查看结果 time.sleep(3) # 退出并关闭会话 driver.quit()重要一定要调用driver.quit()而不是driver.close()。quit()会关闭整个驱动会话断开与Appium服务器和设备的连接而close()在移动端测试中行为可能不确定通常只关闭当前窗口不适用于原生App。将以上所有代码块按顺序组合到一个.py文件中在启动Appium服务器在命令行输入appium并连接好手机后运行这个Python脚本你就能看到手机自动打开设置并点击关于手机了。这就是你的第一个自动化测试脚本5. 进阶技巧让脚本更健壮与可维护能跑起来只是第一步写出能在项目中稳定运行、易于维护的脚本才是真正的挑战。5.1 智能等待告别time.sleep在脚本里到处写time.sleep(5)是初级做法它让测试变得缓慢且不可靠网络或设备慢时5秒可能不够快时又浪费等待时间。Appium提供了两种智能等待隐式等待Implicit Wait在创建驱动后设置一次对整个驱动生命周期有效。它告诉驱动在查找元素时如果立即没找到可以轮询等待一段时间。driver.implicitly_wait(10) # 单位秒设置了隐式等待后像find_element这样的操作如果没立刻找到元素会最多等待10秒期间每隔一段时间重试找到了就继续超时就抛异常。显式等待Explicit Wait更灵活、更推荐的方式。针对某个特定条件进行等待条件满足则继续超时则报错。需要配合WebDriverWait和expected_conditions使用。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待“关于手机”这个元素出现最多等15秒 wait WebDriverWait(driver, 15) about_phone wait.until( EC.presence_of_element_located((AppiumBy.ANDROID_UIAUTOMATOR, ‘new UiSelector().text(“关于手机”)‘)) ) about_phone.click()显式等待的优势精准控制只在需要的地方等待条件多样元素可点击、元素可见、文本出现等。这能极大提升脚本执行速度和稳定性。5.2 页面对象模型Page Object Model, POM这是UI自动化测试中最核心的设计模式。它的思想是将每个页面或页面片段封装成一个类页面的元素定位符和操作这个页面的方法都封装在这个类里。测试用例则通过调用这些页面对象的方法来完成操作。好处高可维护性当页面UI变动时你只需要修改对应页面对象类中的元素定位符所有用到这个元素的测试用例都自动生效。高可读性测试用例读起来就像业务文档“登录页面.输入用户名().输入密码().点击登录()”。低冗余避免了在测试脚本中到处散落着重复的元素定位代码。一个简单的POM示例# base_page.py - 基础页面类封装公共方法 class BasePage: def __init__(self, driver): self.driver driver self.wait WebDriverWait(driver, 10) def find_element(self, by, locator): return self.wait.until(EC.presence_of_element_located((by, locator))) # settings_page.py - 设置页面对象 class SettingsPage(BasePage): # 元素定位符 SEARCH_BAR (AppiumBy.ID, “com.android.settings:id/search_action_bar”) ABOUT_PHONE_MENU (AppiumBy.ANDROID_UIAUTOMATOR, ‘text(“关于手机”)‘) def click_about_phone(self): about_elem self.find_element(*self.ABOUT_PHONE_MENU) # *用于解包元组 about_elem.click() return AboutPhonePage(self.driver) # 返回下一个页面对象 # about_phone_page.py - 关于手机页面对象 class AboutPhonePage(BasePage): MODEL_INFO (AppiumBy.XPATH, “//*[contains(text, ‘型号’)]/../android.widget.TextView[2]“) def get_model_number(self): model_elem self.find_element(*self.MODEL_INFO) return model_elem.text # test_case.py - 测试用例 def test_about_phone_info(): driver webdriver.Remote(‘http://localhost:4723‘, desired_caps) settings_page SettingsPage(driver) about_page settings_page.click_about_phone() model about_page.get_model_number() print(f“设备型号是: {model}“) assert model is not None driver.quit()虽然初期搭建POM结构需要多一些设计但对于长期维护和团队协作来说收益巨大。5.3 异常处理与日志记录自动化脚本运行在复杂的环境中网络波动、应用卡顿、弹窗干扰都可能导致失败。良好的异常处理和日志能帮你快速定位问题。import logging from selenium.common.exceptions import NoSuchElementException, TimeoutException # 配置日志 logging.basicConfig(levellogging.INFO, format‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) logger logging.getLogger(__name__) def safe_click(element_locator): “”“一个安全的点击函数包含重试机制”“” max_retries 3 for attempt in range(max_retries): try: element WebDriverWait(driver, 10).until( EC.element_to_be_clickable(element_locator) ) element.click() logger.info(f“成功点击元素: {element_locator}“) return True except (NoSuchElementException, TimeoutException) as e: logger.warning(f“第{attempt1}次点击尝试失败: {e}“) if attempt max_retries - 1: logger.error(f“元素{element_locator}点击失败已达最大重试次数”) # 这里可以附加截图操作 # driver.save_screenshot(‘click_failed.png‘) raise time.sleep(2) # 等待2秒后重试 return False在关键操作步骤前后添加logger.info记录在捕获异常时使用logger.error并保存截图driver.save_screenshot(‘error.png’)这些信息是后期分析测试失败原因的黄金资料。6. 常见问题排查与实战心得即使按照教程一步步来你也一定会遇到各种问题。这里我总结了一些最高频的“坑”和解决办法。6.1 连接类问题问题adb devices列表为空或设备状态为unauthorized。排查检查USB线是否完好、USB调试是否开启、电脑是否安装了正确的手机驱动Windows上常见。尝试重启adb服务adb kill-server然后adb start-server。手机上确认弹出的“允许USB调试”对话框。问题运行脚本时报错提示无法连接到http://localhost:4723。排查确认Appium服务器是否已经启动。在命令行输入appium后应该看到服务器日志输出并提示listening on 0.0.0.0:4723。检查是否有其他进程占用了4723端口。6.2 会话启动类问题问题session not created: Could not find a driver for...排查这是Appium 2的典型问题。确认desired_caps中的automationName是否正确如UiAutomator2。并通过appium driver list确认该驱动已安装。如果没有使用appium driver install命令安装。问题An unknown server-side error occurred while processing the command. Original error: Cannot start the ‘com.example.app‘ application...排查首先检查appPackage和appActivity名称是否完全正确。对于非系统应用确保APK已经安装到设备上可以用adb install安装。有时需要指定APK的绝对路径使用app这个capability“app”: “/path/to/your/app.apk“。6.3 元素定位与交互类问题问题脚本报错NoSuchElementException但用Appium Inspector一个元素检查工具明明能看到这个元素。排查等待问题最常见。元素还没加载出来脚本就去找了。务必使用显式等待WebDriverWait。上下文问题混合应用Hybrid App或WebView中需要先用driver.switch_to.context(‘WEBVIEW_‘)切换到WebView上下文才能定位网页元素。定位符问题页面可能有多个相同属性的元素你的定位符不够唯一。尝试使用更精确的XPath或者结合多个属性定位如//android.widget.Button[text“确定” and resource-id“ok_btn”]。动态内容元素的resource-id或text可能是动态生成的。尝试使用contains、starts-with等XPath函数进行模糊匹配。问题Element is not clickable at point... Another element would receive the click排查元素被遮挡如弹窗、蒙层。先处理掉遮挡物关闭弹窗或者尝试用driver.execute_script(‘mobile: scroll‘, {‘direction‘: ‘down‘})Appium特有命令滚动到元素可见区域再尝试点击。也可以使用element.click()的替代方案driver.execute_script(‘arguments[0].click();‘, element)通过JavaScript直接点击。6.4 性能与稳定性问题问题脚本运行速度慢不稳定时好时坏。优化方向减少不必要的等待用显式等待替代固定的sleep。优化定位符优先使用ID或accessibility id它们通常最快。XPath遍历较慢尽量避免//开头的全局搜索。避免重复查找对同一个元素找到后存储到变量里重复使用不要每次操作都重新查找。设备状态关闭不必要的后台应用保证手机有足够的内存和电量。在稳定的网络环境下运行。升级版本确保Appium Server、客户端库、驱动都是较新的稳定版本。自动化测试不是一蹴而就的它是一个不断调试、优化和积累经验的过程。每次遇到问题并解决它你对整个系统的理解就会加深一层。从搭建环境到写出第一个脚本再到用POM设计模式组织代码最后能从容处理各种异常这个过程本身就是一个测试工程师成长的缩影。记住核心价值不在于自动化了多少用例而在于通过自动化你更深刻地理解了你的应用并建立了一套快速反馈质量的可靠机制。
返回列表