本文摘要:重点介绍了appium方案与其他方案的优缺点对比,以及在环境配置、原生控件查找、图片识别方面的关键知识和常用问题解决方法。本文适合:只有单一iOS开发或者自动化测试背景的人员,作为辅助文档阅读;不适合作为新手第一篇文档,或者已同时熟练掌握iOS开发、appium自动化测试的人员阅读。
一、前言
游戏发行业务中,对游戏进行测试是保证游戏质量重要的一环。传统人工测试的方法费时费力、容易出错,所以自动化测试技术显然才是更好的解决方案。而 appium
就是自动化测试的最优秀的方案之一,新手上路可以通过 appium 官方的 Getting Started - Appium 快速入门。
二、iOS UI 测试方案对比
在讲解appium
的相关内容之前,我们先看看目前有哪些主流的测试方案可以选择。
iOS的UI测试的技术方案有两个大的方向:
- 原生方向
- 跨平台的方向
方案对比:
方向 | 框架 | 编程语言 | 原生控件查找 | 图片识别 | 更新维护 | 开发体验 |
---|---|---|---|---|---|---|
原生 | XCTest | Objective-C、Swift | 最优 | 没有 | 最优 | 最优 |
跨平台 | appium | Python、JS等 | 有 | 有 | 优 | 一般 |
跨平台 | airtest | Python | 有 | 有 | 一般(iOS) | 优 |
<!-- more -->
2.1 原生
原生方向优势在于原生控件识别的速度以及准确度,以及框架更新维护的及时性。劣势在于没有直接集成图片识别的功能,而图片识别是游戏的自动化UI测试关键的一环。因此原生方向是适合App的自动化UI测试方案,并不适合直接应用于游戏。此外,原生方向还对使用人员有掌握iOS开发的要求,不便于我们iOS开发与测试人员合作开发。
2.2 跨平台
跨平台方向是实现iOS手游UI自动化测试更好的选择。此方向的具体实现有很多,表格举了两个较为典型的例子:appium
以及airtest
。
2.2.1 appium
appium
是开源社区最为流行的移动UI测试框架,支持多种编程语言编写脚本。项目维护更新频繁,bug修复及时。功能方面,原生控件识别、图片识别样样齐全。使用过程遇到的问题在社区中能较快找到解决方法。缺点在于appium的IDE等配套(指免费方案)不完善,且没有针对手游进行专门优化,实际使用需要自己实现较多的脚手架以及轮子。
2.2.2 airtest
airtest
是网易公司专门针对手游优化的UI测试方案,使用Python语言进行编写脚本。IDE、中文文档等配套完善易用,同时也是免费的。缺点在于,单就iOS而言,核心框架 iOS-Tagent
的代码并不开源,且在新版Xcode适配,bug修复等问题上都较慢。使用人员碰到问题往往比较被动,只能通过 Github 提交 issue ,然后静静等待官方修复。
综合考虑后,笔者选择了appium作为iOS手游UI测试方案。
三、appium 环境配置
appium 官方文档非常完善和友好,所以大家可以通过官方文档 Getting Started - Appium 快速上手,本文就简单列出一些关键点,理清一下思路。
安装命令行版 appium 需要使用 npm 命令执行,因为appium是基于node开发的。
代码语言:txt复制npm install -g appium
此外,appium还有一个桌面版,使用Electron编写。从 Github官方仓库 下载安装包,直接安装即可。
桌面版既可用于启动appium命令行版服务器,也可用于控件查找调试以及自动录制生成脚本,推荐新手安装。但桌面版本身并不是一个IDE,需要使用另外的IDE编写UI测试脚本并运行。
安装完appium,重要的一步是确保WebDriverAgent
工程的WebDriverAgentRunner
target编译通过。找到工程的位置后,调整对应target的证书以及描述文件即可。
# 命令行版appium WebDriverAgent工程默认位置
/usr/local/lib/node_modules/appium/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj
# 桌面版appium WebDriverAgent工程默认位置
/Applications/Appium.app/Contents/Resources/app/node_modules/appium/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj
其他问题,Getting Started - Appium 已经写得较清晰,不再赘述。
四、appium 原生控件查找
下文所提控件
一般都特指iOS原生控件
,如UIButton
、UITextField
等。
控件查找主要应用于原生SDK界面的自动化操作,如输入账号密码、点击SDK的登录按钮等。进行自动化操作,重点就在控件查找;而找到控件以后与其交互,只需调用对应的click之类API,这个相对直接简单的。
appium 的原生控件查找的策略,笔者根据是否需要在iOS端提前适配,将其分为两种:
- 侵入式
- 非侵入式
4.1 侵入式查找策略
侵入式查找策略
原理是iOS端的对应控件提前适配一个标识符accessibility_id
,然后UI测试脚本凭借该标识符查找到对应控件。代码示例如下:
// iOS端:Swift
loginBtn.accessibilityLabel = "login_vc_login_btn"
代码语言:txt复制# appium脚本代码端:Python
driver.find_element_by_accessibility_id('login_vc_login_btn')
侵入式方案优势在于测试端的自动化脚本容易编写。而劣势显而易见是,得为众多的UI控件添加唯一标识符(如果两个控件标识符相同,情况会变得复杂),对开发人员来说比较麻烦,尤其是在同时开发维护多套SDK的时候。
此外,侵入式方案的查找效率往往会比下面介绍的非侵入式方案更慢,可以使用桌面版appium进行控件查找时间测试。
4.2 非侵入式查找策略
非侵入式查找策略
原理是通过规则匹配的方式查找控件,无需iOS端提前适配,且识别速度会更快。
4.2.1 ios-class-chain 上手使用
非侵入式查找策略有多种,但此处只介绍其中的集大成者 ios-class-chain
查找策略。先看代码:
# appium脚本代码
driver.find_element_by_ios_class_chain('**/XCUIElementTypeButton[`label == "登录"`]')
这是典型的使用场景,作用是:查找label属性等于登录的按钮元素,别的元素也能以类似的方式进行查找。find_element_by_ios_class_chain
是appium提供的API。函数需要的参数, 本文称之为selector
。
4.2.2 ios-class-chain selector分析
使用 ios-class-chain
查找策略的关键就在于编写 selector
,我们还是用上面的例子对 selector
进行拆解分析。
# selector
'**/XCUIElementTypeButton[`label == "登录"`]'
**/
符号放在了 selector
开头,作用是避免在根层级直接查找元素。此外,正如 ios-class-chain
名称本身所示,我们能链式组合出更精确更复杂的 selector
去满足查找需求,**/
符号此时可能出现在 selector
中间。含义指后面的元素不是当前层级的直接子代(child),是间接子代(子代的子代,descendant)。
**/XCUIElementTypeCell[`name BEGINSWITH "D"`]/**/XCUIElementTypeButton
XCUIElementTypeButton
是按钮元素在iOS的XCTest框架的枚举名称表示。查看 XCTest文档 可以查看更多其他可用控件元素名称。
[`label == "登录"`]
方括号里面的表达式叫谓词表达式,是被查找控件的约束条件。
此谓词表达式的含义是:label属性等于登录。除了表示相等的==
运算符,表达式能用的运算符,还有逻辑表达式的 AND
,字符串比较的BEGINSWITH
等等。appium的 iOS谓词指南以 及苹果的 谓词编程指南 作了更详细的介绍。
表达式左边使用了label
属性。label一般是用户能直接看到的内容。如一个文字按钮文本写的是立即登录,那按钮label属性值就是立即登录
。但如果这个按钮的内容不是文字,而是一张图片,那按钮label属性值是由图片的文件名经过命名规则的转换而来的。编写脚本的人员往往不知道图片文件名,这时候可以用桌面版appium调试工具查看最终的selector
结果。
表达式左边还有一个属性也很常见:name
。假如在 iOS 端已经给控件提前适配了标识符(参考侵入式查找策略一节),名为:ctrl_access_id
,谓词表达式就可写成:
[`name == "ctrl_access_id"`]
4.2.3 ios-class-chain 总结
appium的 ios-class-chain
查找策略会将 selector
转换成一系列苹果原生API(XCUITest
)的直接调用,而不是递归地构建整个UI树,所以往往会比其他策略更高效。再加上此策略无需iOS端提前适配,综合下来,是笔者首选使用的查找策略。
它的劣势在于 selector
编写会比直接的标识符复杂一些。所幸我们只要掌握要一些常用规则,足以应付多数情况,而且桌面版的appium也能作为参考工具。
五、appium 图片识别
appium能实现原生控件查找,是因为底层的 WebDriverAgent
框架把脚本命令转换了成原生 XCTest
框架的调用。而游戏引擎生成的游戏画面内容不能像原生控件一样去查找,因此就需要用到图片识别的技术。
appium的图片识别依赖于 openCV
,请先根据命令行引导安装好环境,否者在调用 find_element_by_image
API时会抛出异常。
图片识别值得讲的点不如原生控件查找的多。比较常用的一些配置和笔者碰到的问题例举如下,供大家参考:
getMatchedImageResult
: 设置为True能保留查找到的图片的base64字符串表示,从而进行图片识别的debug。imageMatchThreshold
: 控制图片准确度阈值,默认值是0.4。实际使用发现经常会误识别,所以笔者一般会调高此值。fixImageTemplateScale
: 调整基准图片的比例。图片识别最终是转换成了屏幕坐标点。一般手动截图往往是是2倍或者3倍图,因此需要先调整图片分辨率比例,才能转换成正确的坐标点。这个配置理论上是用来自动调整比例的。但在编写本文的此时,这个配置实测有bug,笔者只能用自己的脚本另行处理。
六、总结
本文简要对比了游戏自动化测试方案、appium的入门参考知识以及常见问题解答。appium 原生控件查找一节重点分析了ios-class-chain
策略的使用方法。
在游戏自动化测试方案选型问题上,如果只是简单使用,现成的整合方案如 airtest
是较好的选择。如果想长期稳定使用、且有能力进行脚手架开发的情况下,可考虑采用 appium
这样的跨平台方案。
在appium的控件查找方案问题上,如果想要脚本端容易编写,可以选择提前适配 accessibility_id
的侵入式方案。如果不能(想)对源代码进行修改,那本文重点介绍的非侵入式策略 ios-class-chain
是首选。
大家有任何问题,欢迎在评论区一起交流啊~
七、参考链接
- https://appium.io/docs/en/about-appium/getting-started/
- https://appiumpro.com/editions/8-how-to-find-elements-in-ios-not-by-xpath
- https://github.com/facebookarchive/WebDriverAgent/wiki/Class-Chain-Queries-Construction-Rules