Python+Appium自动化测试,上手实操的完整行军路线
写这篇东西的起因是,最近在带一位刚转岗的同事做移动端回归测试,他之前只写过接口自动化,第一次接触真机上的UI自动化,对着Appium那一堆概念和环境配置折腾了两三天,还是卡在“环境起来了但脚本就是跑不起来”的阶段。我陪他把整个链路从零过了一遍,过程中发现很多卡点其实是共性的,跟网上那些教程对不上号:要么是版本不匹配,要么是设备和驱动的问题被一笔带过,要么干脆不讲原理直接让你复制粘贴。所以干脆把这一整套从环境搭建到脚本落地的完整步骤整理出来,既能帮他存档,也能给刚入坑Appium自动化测试的朋友一条能走通的路。
这套东西适合谁?说白了就是两类人:一类是已经在做测试、想从手工用例往自动化方向转的,另一类是开发同学想验证自己App核心流程稳定性的。文章会覆盖Python和Appium这套组合的完整配置过程,从“为什么要这么搭”到“每一步怎么操作”,再到跑起来之后怎么排查问题,尽量让你看完之后能照着把第一个可用的脚本跑通,而不是只停留在安装成功的假象里。
1. 内容整体设计与思路拆解
1.1 为什么是Python和Appium这对组合
先聊个最关键的问题:移动端UI自动化框架那么多,为什么偏偏选Python + Appium?真不是跟风,这套组合在工程落地层面有几个非常实际的优势。
Appium的设计理念是“一个框架管所有平台”。它基于WebDriver协议扩展而来,相当于给Android和iOS各开了一扇统一的门,你用同一套API去写Android脚本,将来换到iOS上绝大多数逻辑可以直接复用。这对测试团队来说意味着什么?意味着资产沉淀不用分两套做,维护成本直接砍半。而Python这边,语法简洁、生态成熟,跟Appium的Python Client库配合起来,写用例的效率确实比Java要快不少。当然Java也能做,但如果你团队里没有历史包袱,Python几乎是入门和落地速度最快的选择。
从技术架构上说,Appium中间隔了一层。它本身是一个HTTP服务器,接收来自脚本的指令,再把这些指令翻译成对应平台能理解的动作。Android上调用UIAutomator2,iOS上调用XCUITest。这种解耦设计有个很大的好处:被测App怎么开发的不重要,测试代码也不依赖App源码,真正做到了“黑盒驱动”。自动化测试的地基就是这套黑盒思想,你只关心用户能看到的界面,不关心内部实现。
1.2 整体流程的四个阶段
把整个自动化测试的构建过程拆开来看,本质上就是四步循环:准备环境、启动会话、定位操作、断言收尾。这四步听起来简单,但每一步都有坑。
准备阶段是大多数人第一次放弃的地方。Python装好了、Appium Server启动了、手机连上电脑了,结果一跑脚本就报Session创建失败,这种问题九成出在环境配置细节上,比如驱动版本不对、平台版本没写对、手机没有开启开发者模式。所以这部分我会写得特别细,版本号、路径、开关状态,全部按实操环境来。
会话启动指的是脚本跟Appium Server建立连接的过程。这个阶段最关键的是Desired Capabilities,这串配置字典相当于告诉Server“我要测什么设备、什么系统、什么App”。很多人不理解为啥要写这些参数,简单类比一下:你去餐厅点餐,菜单上写着菜名、口味、桌号,服务员才知道该往哪送。Capabilities就是你的点餐单,缺一个字都上不了菜。
定位操作是最核心也最花时间的环节。元素能不能被稳定找到,直接决定脚本的成功率。现在Appium支持多种定位方式,ID、ClassName、XPath、UIAutomator等,但实际用下来,没有一种方式能包打天下,需要结合页面特点做选择。这部分我会用一个真实案例来拆解,为什么某些定位方式会失败,正确姿势是什么。
断言收尾是最容易糊弄但其实最重要的一步。很多初学者跑通脚本就以为万事大吉,屏幕上弹了个Toast就算成功。实际上,一次完整的自动化测试,一定要有明确的断言,说清楚“这个页面出现了什么,所以测试通过”。没有断言的脚本,跑一千遍都证明不了任何事情。
2. 核心细节解析与实操要点
2.1 工具选型:Appium Desktop到底该不该用
关于工具这块,很多教程会让你先装Appium Desktop,也就是那个带图形界面的客户端。但我在实际项目里用的频率极低。为什么?因为真正投入到自动化流水线里之后,脚本都是通过命令行或者测试框架直接驱动Server的,图形界面只在调试元素定位的时候有点用。
我的建议是:别把Appium Desktop当主力工具,但可以用它来完成一件事——启动服务。新版Appium Desktop集成了 Inspector 功能,能让你直观地看到当前页面元素树,这对定位元素极其有帮助。你可以在电脑上看到手机的实时屏幕,点击某个按钮,右侧就显示对应的元素属性,这比盲写XPath高效太多了。
不过要提醒一句:Inspector连接手机的时候,有时候会占用adb通道,导致你命令行里的adb命令卡住。遇到这种情况,先断开Inspector的连接再操作,不然后面跑脚本会莫名其妙超时。
2.2 环境依赖版本对照:最容易翻车的环节
说实话,Appium自动化90%的报错都出在版本不匹配上。Appium Server、对应平台的驱动、Python Client库、Android SDK Platform Tools,这四个东西的版本必须互相兼容,差一个版本号可能就导致Session根本创建不起来。
我先给出一套当前稳定可用的组合,这套组合我在多个项目里验证过,跑原生App和WebView混编App都没问题:
| 组件 | 版本建议 | 说明 |
|---|---|---|
| Python | 3.10+ | 太旧的版本对第三方库支持不好 |
| Appium Server | 2.x | 新架构,驱动按需安装 |
| UiAutomator2驱动 | 2.x | Android自动化核心驱动 |
| Appium-Python-Client | 2.x | 对应Appium 2.x协议的客户端 |
| Node.js | 16+ | Appium 2.x基于Node.js运行 |
| Android SDK Platform Tools | 最新版 | 提供adb等基础命令 |
这里有个新手最容易踩的坑:网上很多教程还在用Appium 1.x时代的写法,比如通过appium-doctor去检查环境,或者通过desired_capabilities字典传参。这些写法在Appium 2.x里大部分还能兼容,但官方已经不推荐了,尤其是驱动安装方式变化很大。Appium 2.x要求你单独安装驱动,比如Android的驱动就是一条命令的事,装完之后才能正常创建会话。
还有一点要特别留意,很多人的电脑上其实装了不止一套Java环境,或者Android SDK路径写错了,导致Appium找不到平台工具。我自己习惯把ANDROID_HOME环境变量指到明确的目录,然后platform-tools和build-tools两个子目录都要存在。Windows下更省事的做法是把adb.exe所在目录加进系统PATH,否则后续很多操作要写全路径,非常痛苦。
查版本的时候,统一用命令来确认:appium --version看Server版本,adb --version看平台工具版本,pip show Appium-Python-Client看客户端库版本。如果你发现三者的版本组合跟上面表格出入很大,先调整到接近的版本组合再往下走,避免踩到版本坑。
3. 实操过程与核心环节实现
3.1 环境搭建完整流程
先说Windows环境,因为大部分人开发机是Windows。前提是你已经装好了Python 3.10+和Node.js 16+,这两个没装的话先搞定它们。装好之后,打开命令行工具,依次执行下面的步骤。
安装Appium Server,新版用npm直接全局安装:
npm install -g appium安装完成后验证一下:
appium --version接着安装Android驱动。Appium 2.x里驱动是分开装的,执行:
appium driver install uiautomator2装完可以通过appium driver list查看已安装的驱动。这一步如果网络不佳可能会超时,多试几次或者配置npm镜像可以解决。
再装Python客户端库:
pip install Appium-Python-Client以上三步搞定之后,启动Appium服务:
appium看到类似Appium REST http interface listener started on 0.0.0.0:4723的输出,说明服务已经起来了,默认监听4723端口。这个端口是客户端脚本连接Server的入口,后面写脚本时要保持一致。
然后准备Android设备。打开手机的开发者选项,把USB调试打开。用数据线连上电脑后,命令行执行:
adb devices如果看到device状态,说明设备连接正常。如果显示unauthorized,需要在手机上点击允许USB调试的弹窗。如果什么也没显示,多半是驱动问题,需要装手机厂商的USB驱动。
最后准备被测App。最简单的办法是直接下载一个App的APK安装包,命令安装:
adb install app-debug.apk装完之后用下面的命令确认包名和启动Activity:
adb shell pm list packages | grep <关键词>注意,从Android 10开始,部分设备查看启动Activity会有限制,可以用adb shell dumpsys window | grep mCurrentFocus查当前前台运行的App包名和Activity,这种方式更靠谱。
3.2 Desired Capabilities配置的完整解读
Dev环境就绪了,脚本要能连上Server,靠的就是Capabilities配置。下面给出一份最常用的配置,逐一解释每个参数的意义。
from appium import webdriver desired_caps = { "platformName": "Android", # 平台名,Android或iOS "appium:platformVersion": "13", # 设备系统版本 "appium:deviceName": "Android", # 设备名,Android下可任意 "appium:appPackage": "com.example.app", # 被测App包名 "appium:appActivity": ".MainActivity", # 启动Activity "appium:noReset": True, # 是否不重置应用数据 "appium:automationName": "UiAutomator2", # 自动化引擎 "appium:ensureWebviewsHavePages": True, "appium:nativeWebScreenshot": True, "appium:newCommandTimeout": 3600, } driver = webdriver.Remote("http://localhost:4723", desired_caps)逐个说下关键点。platformVersion必须和真机系统版本一致,写错了会直接导致Session创建失败。deviceName在Android下其实不影响连接,但按照规范还是要填。appPackage和appActivity就是刚才用adb命令查出来的值,这是Appium知道“启动哪个App、从哪个页面开始”的唯一线索。
noReset这个参数特别实用。默认情况下Appium会在每次会话前清空App数据,如果你在调试阶段,每次都要重新登录或者重新走引导页,会非常烦人。设成True之后,App的数据会被保留,测试速度会提升很多。但如果你是在做回归验证,希望从干净状态开始,那就设成False。
automationName现在默认就是UiAutomator2,但显式写出来能避免一些版本兼容的怪问题。newCommandTimeout设置的是客户端没发新命令时,会话保持的最长时间,单位是秒。测试脚本里如果两个操作间隔很久,这个值给太小会导致会话中断,默认给个3600秒比较稳妥。
启动代码里有个小细节,driver = webdriver.Remote("http://localhost:4723", desired_caps)这一句会直接阻塞,直到Appium Server成功创建会话返回,最长可能等几十秒。如果一直卡在这里,大概率是App启动失败或者Capabilities配置有问题,等它超时报错会给出真正的原因。
3.3 使用pytest组织自动化测试用例
只是把单个脚本跑通,还不足以满足日常自动化测试的需要。真实项目中,我们通常用pytest来管理用例,提供用例调度、断言、报告这些能力。
基本项目结构可以这样规划:
project_root/ ├── conftest.py # pytest的全局配置,负责driver的创建和回收 ├── pytest.ini # pytest配置文件 ├── config.py # 存放设备和App的配置信息 ├── test_cases/ # 测试用例目录 │ ├── test_login.py # 登录模块用例 │ └── test_home.py # 首页模块用例 └── pages/ # Page Object模式的对象库 ├── login_page.py └── home_page.pyconftest.py 里可以写一个fixture来统一管理driver的创建和销毁:
import pytest from appium import webdriver from config import desired_caps @pytest.fixture(scope="session") def driver(): dr = webdriver.Remote("http://localhost:4723", desired_caps) yield dr dr.quit()这样每个测试用例只需要在参数中声明driver,pytest会自动注入。测试方法里定位元素并执行操作,然后通过断言判断结果是否符合预期:
def test_login(driver): driver.find_element(by=AppiumBy.ID, value="username").send_keys("test_user") driver.find_element(by=AppiumBy.ID, value="password").send_keys("123456") driver.find_element(by=AppiumBy.ID, value="login_btn").click() toast = driver.find_element(by=AppiumBy.XPATH, value="//*[contains(@text, '登录成功')]") assert toast is not None, "登录成功的提示未出现,用例失败"这种结构有几个好处:一是用例之间互相独立,不会因为某个用例失败拖累其他用例;二是使用Page Object模式后,当界面变化时只需要修改对应的Page类,用例层几乎不用动。
3.4 元素定位实操:Id、ClassName、XPath怎么选
定位元素是整个自动化测试中最花时间也最考验功力的环节。定位方式选得好,脚本稳定得让人感动;选不好,今天能跑明天就挂,最后你对自动化的信心会一点点磨干净。
优先级最高的是ID定位。原生Android控件通常都有resource-id,这种定位方式最稳定。写法是driver.find_element(AppiumBy.ID, "com.example.app:id/btn_login")。不过现在很多App用跨平台框架开发(比如Flutter、React Native),界面上不一定有标准ID,这时就要考虑其他方式。
Text定位适合按钮和文本,比如页面上的“登录”、“确认”这种固定文案。写法是AppiumBy.XPATH,配合text属性,例如//*[@text='登录']。但要注意,如果同屏有好几个“登录”,这个定位方式会直接报错。
XPath是最后的选择,适用范围广,但性能相对较差,而且依赖页面结构。常见的几个场景:没有ID、没有唯一Text、需要在多层节点里找目标。举个例子:
el = driver.find_element( AppiumBy.XPATH, "//android.widget.LinearLayout[@index='1']//android.widget.TextView[@text='确定']" )这是一种不推荐的写法,因为index是动态的,页面顺序一变就挂。更合理的方式是结合相对路径和属性组合。从上往下定位或者从父节点往下规范子节点,通常稳定性会更好。
定位的关键思路是想办法构造“当前页面的唯一特征”。比如登录页的输入框,虽然没有唯一ID,但如果它是页面里唯一一个文本框,就可以用//android.widget.EditText来定位。再比如一个底部Tab栏,假设三个Tab都有对应的文本,就可以用“文本+位置”的组合。
拿到元素之后,还有个细节经常被忽略:检查元素是否可点击。一些弹出框、折叠面板,元素虽然在DOM树里,但不可见也不可点,脚本直接click会报错。遇到这种情况,可以先判断is_enabled(),或者加个显式等待,等元素真正变成可点击状态再操作。
3.5 开发调试阶段推荐:手动启动Appium还是自动管理
这里顺便聊个经验问题:跑脚本的时候,Appium Server到底怎么起?
本地调试的时候,我习惯自己手动在命令行敲appium启动。原因很简单,你能直接看到Server接收到的每一条请求和日志,脚本卡住了,一眼就能看出是请求没发出还是操作没执行。这个阶段用后台自动启动反而会屏蔽掉很多关键信息。
但切到CI流水线(持续集成流程)或者需要长时间跑稳定回归的时候,手动启动就不合适了。没人会在服务器上半夜爬起来敲命令,这时可以用appium作为后台常驻服务,配合系统的进程管理工具(比如Linux的systemd或者容器化部署)来管理生命周期。甚至在pytest的配置里直接通过程序启动Appium子进程,跑完再关闭,这也是工程化常用的做法。
import subprocess def start_appium(): server = subprocess.Popen(["appium"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) time.sleep(5) # 等待服务完全启动 return server需要提醒的是,Appium Server默认读取当前环境的配置和驱动。如果你的机器上同时存在多个Node版本,或者全局npm包的路径比较乱,先确认which appium指向的是不是你预期的那一个。我见过太多人因为环境变量顺序问题,命令敲下去启动的是旧版本Server,折腾半天找不到原因。
3.6 等待策略:显式等待、隐式等待和强制等待
UI自动化另一个绕不开的话题是等待。App操作有动画、有网络请求,页面元素不是瞬间就出现的。如果脚本不加任何等待,点击一个加载中的按钮,大概率会报ElementNotVisible的错误。
最粗暴也最常见的做法是time.sleep(3),强制等3秒。简单但效率极低,因为你永远不知道是2秒够还是5秒够。为了保险起见,很多人会设置一个足够长的固定时间,结果是每跑一步都白等好几秒,一整个用例跑下来慢得让人怀疑人生。
正经的做法是用显式等待,让程序等到某个条件成立再继续。Appium的WebDriverWait就是干这个的。
from appium.webdriver.common.appiumby import AppiumBy from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC wait = WebDriverWait(driver, 15) element = wait.until( EC.presence_of_element_located((AppiumBy.ID, "login_button")) ) element.click()这段代码的意思是:最多等15秒,每500毫秒检查一次,直到登录按钮出现在DOM里,一旦出现立刻点击。页面加载快的时候,可能1秒就过了;加载慢的时候也不怕,等满15秒按钮还没出现才报超时错误。
隐式等待是另一种思路,它是给driver设置一个全局的等待时间:
driver.implicitly_wait(10)这行设置之后,之后每一次查找元素,都会在找不到的时候先等一会儿再继续,最长到这个时间上限。隐式等待的缺点是它只对find_element生效,对元素定位成功之后的可点击状态判断无效。所以更稳妥的组合是:设置一个合理的隐式等待兜底,关键交互场景再配合显式等待精准控制。这是目前我试下来最平衡的方案。
4. 常见问题与排查技巧实录
4.1 Session创建失败,界面一直卡住
Session创建失败的概率相当高,尤其是第一次跑的人。典型的报错信息是Could not start a new session或者An unknown server-side error occurred。
排查顺序按下面来比较高效:
先看Appium Server的命令行输出,它会直接告诉你哪一步出错了。如果报的是settings delete global相关的,一般是noReset参数和设备状态冲突,尝试把noReset去掉。
再看adb连接状态,执行adb devices确认设备是device而不是unauthorized。如果显示unauthorized,拔线重插,手机会重新弹授权窗口,点击允许。
然后核对Capabilities配置。重点检查platformVersion是不是写错了整型还是字符串格式,以及appPackage和appActivity是否存在。这里有个小技巧,直接跑一次adb shell monkey -p 包名 1,能直接把App拉起来,确保包名和Activity是有效的。
最后检查驱动是否正常。执行appium driver list,确认uiautomator2显示为installed状态。如果显示not installed,重新执行安装命令。
4.2 adb连接不稳定,脚本跑到一半断线
这是一个容易让人崩溃的问题。明明App都启动了,也跑了几个步骤,突然报设备断线,然后整个session失效。
最常见的原因是USB线质量差或者接口松动。别笑,这个原因占比真的非常高。USB线看着能充电,不代表能稳定传输数据。换一根短一点、粗一点的线往往立刻就好。
其次是电脑的USB电源管理策略,系统为了省电会在一定时间后关闭USB端口,导致设备断连。可以在开发机上调整相关策略,关闭USB选择性暂停。
再有就是adb服务本身的问题。如果电脑同时连了多个设备,或者之前有残留的adb进程,也容易冲突。试着执行adb kill-server后重新adb start-server,或者adb reconnect。
如果以上都试过了还是频繁断线,考虑用WiFi模式替代USB连接吧。先USB连接设备,执行adb tcpip 5555开启无线adb,拔掉USB后执行adb connect 设备IP:5555,之后脚本就跑在网络连接上了。这种方式在实验室或者固定测试机上特别实用,彻底摆脱线材问题。
4.3 元素定位不到,或者报NoSuchElement
这个问题最磨人,但解决方案往往藏在细节里。
第一步,确认你要找的元素真的在当前页面。用Inspector看页面树,是所见即所得。如果你在代码里写的定位在某层弹窗或者WebView里,但系统当前的页面根本不对,定位必然失败。尤其是登录后跳转的页面,可能存在转场动画,动画结束前元素找不到,所以等待策略要先到位。
第二步,检查定位表达式。XPath写错是最常见的,尤其是引号嵌套和属性值大小写。Android控件的text属性区分大小写,“登录”和“登陆”就是两个完全不同的值。从Inspector复制出来的XPath可能包含绝对路径,这些路径一旦页面层级有微小变化就失效。尽量用相对路径加上关键属性来重新构造。
第三步,考虑元素是否在WebView里。现在很多App的页面用H5开发,原生定位方式找不到属于正常现象。处理方案是先把context切换到WebView,在WebView的HTML结构里找元素。Appium对此有专门的API:driver.contexts可以查看当前所有上下文,driver.switch_to.context('WEBVIEW_com.example.app')切换之后,就可以用Selenium那套find_element_by_css_selector来定位了。这里要提醒一下,WebView需要打开调试模式,否则Appium根本发现不了这个上下文。
4.4 中文输入失效
自动化过程中经常要给输入框填写中文内容,但直接send_keys中文经常丢字或者无效。这个问题源于Android输入法和Appium的兼容性。
一个绕过去的方案,是在Capabilities里配置unicode键盘和重置键盘:
desired_caps["unicodeKeyboard"] = True desired_caps["resetKeyboard"] = True这两行的作用是让Appium使用它自带的输入法来输入Unicode字符,操作完成后再重置回系统原来的输入法。设置了这两个参数,中文输入的问题基本能解决。
实操中还有个土办法:如果页面某个输入框对文本类型有校验,直接send_keys不行,可以用剪贴板粘贴的方案。先通过adb把文本写入剪贴板,再长按输入框选择粘贴。这个方案比较绕,但确实在一些特殊场景里能救急。
4.5 常见问题排查速查表
| 现象 | 可能原因 | 快速处理方式 |
|---|---|---|
| Session创建失败 | 驱动没装 / 版本不匹配 / 设备未授权 | 确认appium driver list;重插USB并授权;核对Capabilities版本号 |
| 打开App后卡在启动页 | appActivity填写错误 | 用adb shell dumpsys window确认真实Activity名 |
| 元素定位NoSuchElement | 页面未加载完 / 定位表达式不对 / 在WebView中 | 加显式等待;检查表达式;切换context |
| 中文输入无效 | Appium键盘未启用 | 开启unicodeKeyboard和resetKeyboard |
| 点击无响应 | 元素存在但不可点击 / 被其他元素遮挡 | 检查is_enabled();改用坐标点击或用父元素定位 |
| 代码改完不生效 | Appium Server缓存旧代码 | 重启Server / 清理App数据后再跑 |
4.6 实际排障过程中总结的几条独家经验
最后分享几条我在实际项目里沉淀下来的经验。
第一,日志是自动化排查的第一生产力。Appium Server启动后那个命令行窗口别关,它会记录每一次HTTP请求和响应。脚本报错时,从Server日志里能看到很多客户端看不到的信息。比如定位元素失败时,Server日志里会附上当时的页面源码片段,哪怕只有几百行,也能通过搜索关键词快速定位问题。
第二,不要过度依赖坐标点击。坐标点击(tap)是最不稳定的操作方式,屏幕尺寸、分辨率一变,坐标就全错了。只有在实在没有别的定位方式时才用它,而且最好做成配置文件,方便不同设备间切换。
第三,保持用例独立性。一个用例里不要依赖另一个用例的执行结果。比如登录用例执行完,下一个用例假设“已经登录”,这种设计在持续集成里跑一次就会挂一次。要么每个用例自己完成数据准备,要么通过环境初始化统一处理。
第四,尽早引入Page Object模式。哪怕只写个二三十个用例的规模,也能感觉到维护的痛。把所有定位器集中到单独的Page类里,页面改版时只改一处,看起来先慢后快,实际长期维护效率高得多。
5. 从小规模脚本走向工程化落地
脚本能跑通只是开始,真正有挑战的是怎么让这套东西在团队里稳定运行、可持续维护。
自动化测试用例刚建立时,最忌讳一上来就追求大而全的覆盖。头一两个版本建议先把核心链路(登录、主流程、关键业务操作)跑通,稳定之后再逐步扩展。自动化用例的维护成本跟功能的稳定性强相关,最怕那种“写100条用例、每次跑挂50条、挂的还都是同一个页面改版导致的”情况,这种项目很快就会被抛弃。
另一个容易被忽略的点是测试脚本本身也需要版本管理。脚本项目的依赖、环境配置、测试数据,都要跟着代码一起管理,新同事接手或者换一台执行机,都得能一键拉起环境。
在执行策略上,建议先用异步执行的方式在真机或者模拟器上跑通,然后把执行过程接入到持续集成流水线,每次有新的测试包出来就自动跑一遍冒烟测试。这样自动化测试才能真正成为一个项目质量保障的一部分,而不是停留在个人本地的玩具脚本。
6. 一点个人心得
做Appium自动化测试这几年,最大的体会是:这项技术本身的门槛并不高,难的是工程化的耐心和细节。环境问题、设备问题、版本问题,任何一个环节都可能拦住你一整天,但只要你把整套流程梳理清楚,这些坑都是可以提前避开的。
我个人在实际操作中最常给团队的建议是:第一,保持环境配置的统一,依赖写进文档、写进脚本,凡是能自动化的环境设置都自动化;第二,每个用例都要有明确的断言预期,自动化测试的意义在于验证结果,而不是跑通流程;第三,遇到难以定位的元素,先花时间搞清楚页面结构,而不是不断尝试各种定位表达式碰运气。
这套方案的具体配置和步骤上面都完整给出了,照着走,应该能在半天内跑通你的第一个Appium自动化测试用例。之后遇到新问题,记得先看日志,再查环境,最后才是改代码,按这个顺序来,排查效率会高很多。