Appium自动化测试入门:从环境搭建到第一个脚本编写
发布时间:2026/7/10 22:01:13
分类:文化教育
浏览:1234

1. 项目概述为什么从Appium开始如果你刚接触移动应用自动化测试或者是从Web端的Selenium转战过来听到“Appium”这个名字可能会觉得既熟悉又陌生。熟悉的是它号称是“移动端的Selenium”用类似的WebDriver协议来驱动应用陌生的是面对Android和iOS两大平台、真机与模拟器/仿真器、各种驱动和依赖环境搭建的复杂度似乎陡增。我刚开始接触时也被网上各种版本冲突、环境报错的帖子吓到过。但后来我发现只要理清脉络从编写第一个能成功运行的脚本开始后面的一切都会豁然开朗。这个“从安装到运行”的过程不仅仅是跑通一个Demo更是理解Appium整个工作流和生态的绝佳切入点。它能帮你建立起最核心的认知Appium是一个遵循客户端-服务器架构的HTTP服务你的脚本客户端通过发送符合WebDriver协议的指令来控制远端的Appium服务器进而操作手机上的应用。这个过程解决了什么核心问题它让你摆脱了手动点点点的重复劳动为后续的自动化测试套件、持续集成流水线打下了第一块基石。无论你是测试工程师、开发人员还是对自动化感兴趣的技术爱好者亲手搭建环境并跑通第一个脚本都是最具成就感也最扎实的起步。接下来我会带你走一遍我踩过坑、验证过的最稳当的路径从零开始直到看到手机屏幕在你的代码指令下自动操作。2. 环境准备与核心组件拆解在动笔写第一行测试代码之前我们需要一个稳固的“舞台”。这个舞台由几个关键角色构成理解它们各自的作用和相互关系能让你在遇到问题时快速定位。2.1 核心组件Node.js、Appium Server与客户端库首先Appium服务器本身是用Node.js写的所以Node.js是必须的第一个依赖。我建议直接安装最新的LTS长期支持版本从官网下载安装包即可安装时记得勾选“自动安装必要的工具”选项像npm和npx。安装完成后在终端里运行node -v和npm -v能正常显示版本号就说明基础环境OK了。接下来是主角Appium Server。这是接收你脚本指令的核心服务。安装方式很简单通过npm全局安装npm install -g appium。这里有个小坑需要注意如果你之前安装过旧版本的Appium比如1.x最好先全局卸载 (npm uninstall -g appium) 再安装避免冲突。安装成功后运行appium -v应该能看到版本号比如3.5.2。这里提一嘴你搜索词里出现的npm list -g appium命令就是用来查看全局安装的Appium及其位置的像/users/xxx/.npm-global/lib这个路径就是典型的macOS上通过npm全局安装的包位置。但是光有Appium Server还不够。从Appium 2.0开始它采用了插件化架构。Server本身只是一个核心引擎具体的自动化能力比如驱动Android设备或iOS设备由不同的驱动Driver提供。对于Android自动化目前最主流、最稳定的驱动是UiAutomator2。所以安装完Server后你需要单独安装这个驱动appium driver install uiautomator2。这个命令会从Appium的驱动仓库中拉取并安装uiautomator2驱动。你可以通过appium driver list来查看已安装的驱动。最后是客户端库Client Library。Appium Server提供标准的WebDriver接口但我们需要用某种编程语言来调用这些接口这就是客户端库的作用。对于Python官方的客户端库是Appium-Python-Client。它继承自Selenium的Python绑定所以你安装它的时候会自动把selenium依赖也装上。安装命令就是经典的pip install Appium-Python-Client。注意这里的环境顺序很重要。先装Node.js和Appium Server再装所需驱动最后在Python虚拟环境中安装客户端库。很多新手问题都出在顺序错乱或环境混杂上。2.2 移动端环境Android SDK与设备准备我们的脚本最终要控制Android设备或模拟器所以Android开发环境是绕不开的。核心是Android SDK特别是其中的adb(Android Debug Bridge) 工具。adb是连接电脑和Android设备的桥梁Appium底层很多操作都依赖它。对于Mac用户我推荐通过Homebrew安装Android命令行工具brew install android-commandlinetools。安装后需要设置环境变量比如把ANDROID_HOME指向SDK的安装路径并把adb所在目录通常是$ANDROID_HOME/platform-tools加入到系统的PATH中。之后在终端运行adb devices如果能看到设备列表即使是空的说明adb基本可用。设备方面你可以使用真机或模拟器。对于初学者我强烈建议从Android Studio自带的模拟器AVD开始。原因有三第一环境纯净没有真机上各种厂商定制系统的干扰第二方便创建各种型号和系统版本的设备进行测试第三截图、录屏方便。在Android Studio中创建好一个AVD并启动它确保adb devices命令能识别到它会显示类似emulator-5554 device的字样。实操心得真机调试需要开启“开发者选项”和“USB调试”。有时候adb识别不到设备可以尝试1. 换一条质量好的USB数据线2. 在开发者选项里“撤销USB调试授权”后重新连接3. 重启adb服务adb kill-server然后adb start-server。2.3 一个被忽视的关键工具Appium Inspector在你搜索的热词里appium inspector和appium inspector 教程出现的频率很高这恰恰说明了它的重要性。Appium Inspector是一个图形化工具用于定位应用界面上的元素。你可以把它理解为移动端的“浏览器开发者工具”。它的工作原理是连接到一个正在运行的Appium Server会话实时获取设备屏幕截图和UI层级结构类似于XML然后你可以通过点击截图来获取元素的属性如resource-id、text、class、xpath等。这些属性就是你后续编写定位脚本的依据。从Appium 2.0开始Inspector不再随Server捆绑安装需要单独下载。你可以从Appium官方的GitHub Releases页面下载对应操作系统的桌面版Appium Inspector。使用前需要在其配置中填入与你的测试脚本中一致的Capabilities能力参数和Appium Server地址。它是编写和调试定位策略不可或缺的助手能极大提升效率。3. 第一个脚本的逐行解读与编写环境就绪我们来动手编写第一个脚本。我将以一个最简单的目标为例打开Android系统的“设置”应用然后点击进入“电池”选项。这个例子不依赖任何外部APK非常适合入门。3.1 脚本骨架与依赖导入首先创建一个Python文件比如叫first_appium_test.py。我们使用Python内置的unittest框架来组织测试用例因为它简单直接适合演示。import unittest from appium import webdriver from appium.options.android import UiAutomator2Options from appium.webdriver.common.appiumby import AppiumByunittest: Python标准库中的单元测试框架提供了setUp测试前置、tearDown测试后置和断言方法的结构。webdriver: 从appium包导入这是我们创建远程连接的核心。UiAutomator2Options: 这是Appium 2.x推荐的新方式用于设置和管理Capabilities比旧版的字典方式更清晰、类型更安全。AppiumBy: 定义了Appium扩展的一些定位器策略虽然大部分与Selenium的By通用但使用它可以保持一致性。3.2 核心灵魂Capabilities详解Capabilities是一组发送给Appium Server的“指令”或“描述”告诉服务器你想要启动一个什么样的自动化会话。这是连接客户端、服务器和待测应用的纽带理解每个参数的含义至关重要。# 定义Capabilities capabilities dict( platformNameAndroid, # 平台必须是Android或iOS automationNameuiautomator2, # 自动化引擎这里指定我们安装的UiAutomator2驱动 deviceNameAndroid, # 设备名称在Android上可以是任意字符串但通常用于日志标识 appPackagecom.android.settings, # 要启动的App包名 appActivity.Settings, # 要启动的App初始Activity名 languageen, # 设置设备语言 localeUS, # 设置设备地区 # 可选指定UDID当连接多设备时用于区分 # udidemulator-5554 )platformName和automationName这是两个必须且关键的参数。它们告诉Appium Server使用哪个驱动来处理会话。uiautomator2是针对Android 5.0的现代驱动。deviceName在Android环境下这个参数的实际作用不大主要是日志和报告里显示用。即使你的设备叫“MyPhone”这里写“Android”也没问题。但在Selenium Grid或多设备并行时它有标识作用。appPackage和appActivity这是启动特定Android应用的关键。如何获取它们有几个方法1. 问开发2. 如果你有APK文件可以用aapt dump badging your_app.apk | grep package和... | grep launchable-activity命令查看3. 在已安装应用的设备上使用adb shell dumpsys window | grep mCurrentFocus命令查看当前前台应用的包名和Activity。language和locale这些是“可选但推荐”的参数。指定它们可以确保应用在预期的语言环境下启动避免因系统语言不同导致文本定位失败。注意事项Capabilities的键key在Appium 2.x中大部分都需要加上appium:前缀例如appium:appPackage。但是Appium Python客户端的最新版基于Selenium 4的UiAutomator2Options().load_capabilities()方法会自动帮你处理这个前缀所以用字典直接写也没问题这样代码更清晰。但如果你直接用webdriver.Remote(command_executor, desired_capabilities)这种旧式传参就必须自己加前缀。3.3 连接服务器与测试生命周期管理接下来我们定义Appium Server的地址并构建测试类。appium_server_url http://localhost:4723 # Appium Server默认监听4723端口 class TestAppium(unittest.TestCase): def setUp(self): # 将Capabilities字典加载到UiAutomator2Options对象中 options UiAutomator2Options().load_capabilities(capabilities) # 创建WebDriver会话连接到Appium服务器 self.driver webdriver.Remote(command_executorappium_server_url, optionsoptions) # 隐式等待全局设置查找元素的超时时间 self.driver.implicitly_wait(10) def tearDown(self): # 测试结束后退出并关闭会话 if self.driver: self.driver.quit()setUp在每个测试方法以test_开头的方法执行前运行。这里我们初始化驱动会话。webdriver.Remote是建立连接的核心它向http://localhost:4723/wd/hubAppium 2.x后路径简化了发送一个POST请求携带Capabilities。服务器解析后会通过adb命令启动指定的应用并返回一个会话IDsession id后续所有操作都基于这个会话。implicitly_wait(10)设置隐式等待10秒。这是一个非常重要的最佳实践。它意味着后续所有find_element操作如果元素没有立即出现驱动会轮询查找最多等10秒。这能有效避免因网络延迟、应用启动慢或动画导致的“元素找不到”错误。tearDown在每个测试方法执行后运行。driver.quit()方法会向服务器发送删除会话的请求服务器则会关闭被测应用并清理资源。务必确保会话被正确关闭否则会导致端口占用、设备资源残留等问题。3.4 编写测试动作与元素定位现在编写我们的测试用例找到并点击“Battery”电池选项。def test_find_battery(self): # 使用XPath定位器寻找文本内容为“Battery”的元素 battery_element self.driver.find_element(byAppiumBy.XPATH, value//*[textBattery]) # 点击该元素 battery_element.click() # 为了让我们肉眼看到效果等待几秒 import time time.sleep(3)定位策略这里使用了AppiumBy.XPATH。XPath是一种在XML文档中定位节点的语言Android的UI层级通过uiautomator2dump出来就是一种XML结构。//*[textBattery]这个表达式意思是在整个文档中寻找任意节点*且该节点的text属性等于“Battery”。为什么用text定位对于系统设置这种标准应用菜单项的文本通常是固定的、可读性最好的标识。但在定位你自己的应用时优先使用resource-id对应Android中的android:id因为它是开发人员赋予的唯一标识最稳定。如果id不可用再考虑text、content-desc或class。click()执行点击操作。Appium会将该命令转化为对设备的一次触摸事件。最后添加启动测试的代码if __name__ __main__: unittest.main()4. 完整运行流程与现场调试脚本写好了但让它成功跑起来还需要正确的步骤和一点调试技巧。4.1 分步执行与验证启动Appium Server打开一个终端窗口直接输入命令appium。如果一切正常你会看到大量日志输出最后几行通常包含Appium REST http interface listener started on 0.0.0.0:4723这样的信息表示服务器已在4723端口启动成功。让这个终端窗口保持运行。确保设备在线打开另一个终端窗口运行adb devices。你应该能看到你的模拟器或真机设备状态为device。如果显示unauthorized去设备上点击确认“允许USB调试”的提示。执行测试脚本在第三个终端窗口或你的IDE终端里导航到脚本所在目录运行python first_appium_test.py。4.2 预期结果与问题排查如果一切顺利你会看到Appium Server的终端里滚动出现新的日志显示创建新会话POST /session、启动应用等操作。你的Android设备屏幕亮起系统“设置”应用被自动打开。稍作停顿后应用会自动滑动并点击进入“电池”设置页面。等待3秒后应用关闭。但第一次运行就成功的概率可能没那么高。下面是一些常见错误及排查思路错误Unable to create a new remote session. ...可能原因1Appium Server没启动。检查第一步的终端确认服务器在运行。可能原因2Capabilities配置错误。仔细检查platformName,automationName,appPackage,appActivity的拼写和值。特别是appActivity有时需要完整的包名路径如com.android.settings.Settings但通常以点开头.Settings也可以。最可靠的方式是用adb shell dumpsys window命令去查。可能原因3设备未连接或未授权。再次运行adb devices确认。错误An element could not be located on the page using the given search parameters.可能原因1元素定位表达式写错了。打开Appium Inspector连接到同一个Appium Server和设备打开设置应用查看“Battery”这个文本在UI树中的准确属性。也许它的text是“电池”中文系统或者它外面还有多层布局。可能原因2应用还没加载到那个页面。虽然我们用了隐式等待但可能页面加载时间超过10秒。可以在find_element前加一个显式等待或者增加隐式等待时间。可能原因3需要滚动才能看到元素。如果“Battery”不在首屏需要先滚动。可以改用driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, new UiScrollable(...).scrollIntoView(text(Battery)))这种滚动查找的方式。Appium Server日志报错Original error: Cannot start the com.android.settings application可能原因设备上不存在这个应用或者Activity名不对。在设备上手动确认一下设置应用能否打开。对于模拟器系统应用是肯定存在的。调试技巧多看Appium Server的日志它是排查问题的第一现场。日志级别默认是info如果你需要更详细的信息可以在启动Appium时加上--log-level debug参数。日志里会清晰记录它接收到的命令、发送给adb的指令以及设备的响应。5. 从Demo到实战脚本优化与扩展思路第一个脚本跑通只是万里长征第一步。要让这个脚本具备实战价值还需要进行一系列优化和功能扩展。5.1 优化一使用Page Object模式组织代码直接把定位和操作写在测试方法里在小型demo中没问题但随着用例增多维护将是灾难。Page Object (PO) 模式是自动化测试的核心设计模式。它将每个页面或页面片段抽象成一个类页面的元素定位符和基本操作封装在这个类的方法里测试用例只调用这些方法。例如为“设置”主页面创建一个类class SettingsMainPage: def __init__(self, driver): self.driver driver # 可以在这里定义一些元素的定位符方便管理和复用 self.battery_option_locator (AppiumBy.XPATH, //*[textBattery]) def go_to_battery(self): 从设置主页进入电池设置 battery_ele self.driver.find_element(*self.battery_option_locator) battery_ele.click() # 返回下一个页面的对象实现链式调用 return BatteryPage(self.driver)这样你的测试用例就会变得非常简洁、易读def test_find_battery(self): main_page SettingsMainPage(self.driver) battery_page main_page.go_to_battery() # 接下来可以在battery_page上进行断言或其他操作5.2 优化二更健壮的元素定位与等待策略XPath虽然强大但有时性能较差且易受UI变化影响。Appium提供了更多定位策略ID定位优先选择。driver.find_element(AppiumBy.ID, com.android.settings:id/some_id)Accessibility ID定位对应Android的contentDescription用于无障碍访问也是很好的选择。driver.find_element(AppiumBy.ACCESSIBILITY_ID, Battery)Android UiAutomator利用Android原生框架的定位能力非常强大。# 通过文本定位 driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, new UiSelector().text(Battery)) # 组合条件定位 driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, new UiSelector().className(android.widget.TextView).text(Battery))对于等待除了全局的隐式等待显式等待Explicit Wait在处理复杂条件时更精确。它可以等待某个特定条件成立如元素可点击、元素出现、元素消失等。from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC # 等待“Battery”元素出现最多等15秒每0.5秒检查一次 wait WebDriverWait(self.driver, 15, poll_frequency0.5) battery_ele wait.until(EC.presence_of_element_located((AppiumBy.XPATH, //*[textBattery]))) battery_ele.click()5.3 扩展常用操作与断言一个完整的测试用例除了操作还需要验证结果这就是断言。基本断言unittest提供了assertEqual,assertTrue,assertIn等方法。# 点击电池后可以断言当前页面标题或某个特定元素出现 self.assertIn(Battery, self.driver.page_source) # 简单但粗糙的方式 # 更好的方式是定位页面上的一个特征元素进行断言 battery_summary self.driver.find_element(AppiumBy.ID, com.android.settings:id/battery_summary) self.assertTrue(battery_summary.is_displayed())常用操作封装除了click()还有send_keys()输入文本、swipe()/scroll()滑动、tap()轻触、press_keycode()模拟物理按键等。将这些常用操作封装在Page Object或一个基础的BasePage类里会极大提升代码复用率。5.4 向真实项目迈进配置管理与持续集成当脚本越来越多你需要考虑配置外部化将Capabilities、服务器地址、设备信息等写入配置文件如config.yaml或.json或环境变量避免硬编码。测试数据分离将测试用的账号、文本等数据放在独立的文件如Excel、CSV、JSON中。日志与报告使用Python的logging模块记录运行日志。集成测试报告框架如pytest-html、Allure生成美观的测试报告。集成到CI/CD将你的测试脚本放入Jenkins、GitLab CI等持续集成工具中设定触发条件如每日构建、代码合并后实现自动化回归。6. 避坑指南与高频问题实录结合我自己的踩坑经历和社区常见问题这里总结一份速查清单。问题现象可能原因排查步骤与解决方案adb命令不识别或报错1. Android SDK未安装或路径未配置。2. 环境变量PATH未包含platform-tools目录。1. 确认已安装Android SDK命令行工具。2. 在终端执行echo $PATH查看并确保类似~/Library/Android/sdk/platform-tools的路径在其中。3. 对于Mac在~/.zshrc或~/.bash_profile中添加export PATH$PATH:~/Library/Android/sdk/platform-tools然后source配置文件。Appium Server启动失败端口被占用4723端口已被其他进程可能是之前未退出的Appium实例占用。1. 查找占用端口的进程lsof -i :4723(Mac/Linux) 或netstat -ano | findstr :4723(Windows)。2. 终止该进程kill -9 PID或 任务管理器结束。3. 或者启动Appium时指定其他端口appium -p 4724。真机无法被adb devices识别1. USB调试未开启。2. 数据线仅支持充电。3. 电脑驱动问题Windows常见。4. 设备未授权。1. 进入手机“开发者选项”确认“USB调试”已开启。2. 换一条确认可以传输数据的USB线。3. 在设备连接时查看电脑设备管理器是否有未知设备尝试安装对应品牌驱动。4. 连接时留意手机屏幕是否有“允许USB调试”的弹窗勾选“始终允许”后确定。脚本报错...uiautomator2 driver not installed未安装uiautomator2驱动或Appium Server版本与驱动不兼容。1. 运行appium driver list查看是否已安装uiautomator2。2. 若未安装运行appium driver install uiautomator2。3. 若已安装但报错尝试更新驱动appium driver update uiautomator2。元素能找到但点击无效或点击位置不对1. 元素不可点击状态为disabled。2. 元素被遮挡。3. 坐标点击不准确使用tap或坐标定位时。4. 需要等待元素可点击状态。1. 使用Appium Inspector查看元素属性确认clickable或enabled为true。2. 尝试使用element.click()而非坐标。3. 使用显式等待等待元素可点击WebDriverWait(driver, 10).until(EC.element_to_be_clickable(locator))。4. 对于复杂手势考虑使用TouchAction或W3C ActionsAPI。运行速度慢每一步操作都有明显延迟1. 使用了效率低的定位器如复杂的XPath。2. 隐式等待时间设置过长。3. 设备性能或模拟器速度慢。4. 动画效果未关闭。1. 优化定位器优先使用ID、Accessibility ID。2. 适当减少隐式等待时间或改用针对性的显式等待。3. 在Capabilities中设置disableWindowAnimation: true等参数来关闭系统动画。4. 在开发者选项中关闭“窗口动画缩放”、“过渡动画缩放”等。最后再分享一个我个人的小习惯在项目根目录下创建一个requirements.txt文件记录所有Python依赖如Appium-Python-Client并使用虚拟环境venv或conda来管理项目依赖。这样能最大程度避免包版本冲突让项目在任何新电脑上都能快速搭建起测试环境。从第一个脚本开始就养成好的工程习惯后面的路会好走很多。