网易Airtest:跨平台UI自动化测试框架的实战应用
1. 从零开始认识Airtest:它到底是什么,能帮你做什么?
如果你是一名游戏或者App的开发者、测试工程师,或者只是一个对自动化感兴趣的技术爱好者,那你肯定对“重复劳动”深恶痛绝。想想看,每次版本更新,你都要手动把游戏的所有关卡点一遍,把App的每个功能按钮按一遍,检查有没有崩溃、有没有UI错位、有没有逻辑错误。一次两次还行,十次百次呢?枯燥不说,还容易因为疲劳而出错。这时候,你就需要一个靠谱的“机器人”来替你完成这些重复性的点击和验证工作。网易开源的Airtest,就是这样一个能让你从重复劳动中解放出来的强大工具。
简单来说,Airtest是一个跨平台的UI自动化测试框架。这个名字听起来有点技术范儿,咱们拆开看。“跨平台”意味着它不挑食,无论是Windows上的PC游戏、安卓手机上的App,还是iOS设备上的应用,它都能搞定。“UI自动化测试”就是它干的事情——模拟人的操作,自动去点击屏幕、滑动页面、输入文字,并且检查屏幕上显示的内容是否符合预期。它的核心魔力在于基于图像识别。这是什么意思呢?它不需要你懂复杂的App内部代码结构,你只需要告诉它:“去点击屏幕上这个‘开始游戏’的按钮”,它就能通过截图,在屏幕上找到和这个按钮图片最匹配的区域,然后精准地点击下去。这种方式非常直观,特别适合测试游戏或者那些UI控件难以通过代码直接获取的应用(比如一些用游戏引擎开发的App)。
我第一次接触Airtest是在测试一个Unity开发的手机游戏时。那个游戏很多UI元素是动态生成的,传统的基于控件树的自动化工具根本抓取不到,测试同学每天都要手动跑回归用例,苦不堪言。后来尝试了Airtest,我们直接把需要点击的按钮截图保存下来,写成脚本,让Airtest去自动找、自动点。一下子就把测试效率提升了十几倍,而且再也不会因为手滑点错地方了。所以,无论你是想自动化你的游戏测试流程,还是想给自己开发的App做个冒烟测试集,或者只是想搞个自动刷日常任务的脚本,Airtest都值得你花时间了解一下。它上手门槛低,效果立竿见影。
2. Airtest全家桶:不只是图像识别,还有控件识别利器Poco
很多人刚开始用Airtest,以为它就是靠截图找图。这没错,但只说对了一半。网易推出的实际上是一个完整的自动化解决方案,叫做 AirtestProject。它主要由两个核心框架和一个强大的IDE组成,就像一个组合工具箱,让你能根据不同的测试场景,选择最顺手的那把“螺丝刀”。
第一个核心是Airtest框架本身,也就是我们前面重点讲的基于图像识别的方案。它的工作原理很像我们人眼。你给它一张“目标图片”(比如一个宝石图标),它会在当前设备屏幕上不断地进行图像匹配,计算相似度,找到位置后,就调用底层接口执行触摸操作。这种方式最大的好处是通用性强,几乎适用于任何你能看到的东西,不管是原生控件、游戏贴图还是网页元素,只要能截图,就能尝试自动化。但它的缺点也比较明显:对画面变化比较敏感(比如光线变化、特效遮挡),执行速度相对慢一点(因为要计算图像)。
第二个核心是Poco框架,这是AirtestProject里的另一件“神兵利器”。如果说Airtest是“外观识别”,那Poco就是“内部透视”。它是一款基于UI控件识别的自动化测试框架。对于支持的游戏引擎(如Unity3D、Cocos2dx)和原生应用(Android/iOS),Poco可以直接获取到UI界面的控件树结构。你可以像前端工程师定位网页元素一样,通过id、name、text等属性精准地定位到一个按钮或者一段文本。这种方式速度快、精度高、稳定性好,而且能获取到控件内部的属性(比如一个血条的数字值),实现更复杂的逻辑判断。我个人的经验是,对于支持Poco的应用,优先使用Poco来写脚本,效率和稳定性都会高出一个数量级。
为了方便大家使用这两个框架,网易还提供了 AirtestIDE。这是一个集成的开发环境,你可以把它理解为一个专门为Airtest和Poco打造的“编程工作站”。它最大的亮点是所见即所得和录制功能。你连接上手机后,可以直接在IDE里看到手机屏幕,用鼠标点一下屏幕上的某个位置,IDE就能自动生成对应的点击代码。你甚至可以像录屏一样操作一遍手机,它就把你的操作过程录制成一个可回放的脚本。这对新手来说简直是福音,大大降低了编写自动化脚本的门槛。我们团队的新人,基本上培训一两个小时,就能用AirtestIDE录制出可用的简单测试脚本了。
3. 手把手实战:用AirtestIDE编写你的第一个自动化脚本
光说不练假把式,咱们直接动手,看看怎么在5分钟内创建一个能真正运行的自动化脚本。这里我以最常用的Android手机测试为例,带你走一遍完整流程。
### 3.1 环境准备与设备连接
首先,你需要去AirtestProject的官网下载AirtestIDE。它是绿色免安装的,解压就能用,非常方便。打开IDE后,你会看到一个简洁的界面。第一步就是把你的安卓手机用USB线连上电脑,并开启手机的“开发者选项”和“USB调试”模式。这个步骤和用ADB连接手机是一样的。在AirtestIDE的右侧设备窗口,点击“刷新ADB”,如果一切正常,你应该能看到你的设备号出现。点击“连接”,IDE就会尝试连接手机。连接成功后,你会在IDE中间看到手机的实时屏幕镜像!这意味着你的电脑已经可以控制这台手机了。
这里有个我踩过的坑要提醒你:确保电脑上只连接了一台待测安卓设备。如果连了多台,ADB可能会选错设备,导致连接失败。如果遇到连接问题,可以尝试在命令行用adb devices命令检查设备状态,或者重启一下ADB服务。连接iOS设备会稍微复杂一点,需要安装tidevice等工具,并且需要苹果开发者证书,对于初学者,建议先从安卓设备开始玩起。
### 3.2 图像识别与点击:录制你的第一个操作
环境准备好,我们就可以开始“录制”脚本了。假设我们要自动化测试一个计算器App,目标是自动完成一个加法运算“5+3=”。
- 截取目标图像:在AirtestIDE中看到计算器界面后,我们想先点击数字“5”。在IDE顶部的工具栏,找到那个像小剪刀一样的“截图”工具,点击它。这时你的鼠标会变成一个十字准星,把它移动到手机屏幕镜像的数字“5”按钮上,拖拽框选住整个按钮,然后松开鼠标。神奇的事情发生了:IDE不仅截取了一张“5.png”的小图片保存在脚本目录,还在左边的代码编辑区自动生成了一行代码:
touch(Template(r“tpl1234567890.png”))。这行代码的意思就是,在屏幕上查找与“5.png”这张模板图片匹配的区域,并进行点击操作。 - 继续录制:接着,我们用同样的方法,截取“+”号按钮,生成点击“+”的代码;再截取数字“3”,生成代码;最后截取“=”号按钮。这样,我们就通过纯“鼠标操作”,生成了一段完整的自动化脚本。你完全不需要手写一行代码。
- 运行与调试:点击IDE上方的运行按钮(绿色的三角形),Airtest就会开始执行你的脚本。你会看到手机屏幕被自动操作,依次点击5、+、3、=,最终显示结果8。如果运行失败,比如某个按钮没找到,IDE会用红色框标出失败的地方,并提示相似度。你可以调整截图的范围,或者修改代码中的
threshold(相似度阈值)参数来提高识别的容错率。
通过这个简单的例子,你应该能感受到AirtestIDE的便捷性了。它把图像识别这个复杂的技术,包装成了“截图-生成代码”这样简单的动作,让UI自动化的起点变得非常低。
4. 进阶技巧:结合Poco进行更精准、更强大的控件级操作
虽然图像识别很方便,但在实际项目,尤其是长期维护的自动化测试中,我们更追求稳定和高效。这时候,Poco框架就该登场了。我们来看看怎么在AirtestIDE里使用Poco。
### 4.1 启用Poco并查看UI控件树
首先,确保你的被测应用是Poco支持的(比如Unity应用、Android原生应用)。对于Unity游戏,你需要让开发同学在打包时集成Poco的SDK。对于Android原生App,AirtestIDE通常可以自动注入辅助服务来获取控件信息。在IDE连接设备后,点击设备窗右上角的“Poco”按钮,选择对应的模式(比如Android、Unity)。如果初始化成功,你会看到一个新的“Poco辅助窗”弹出来。
这个辅助窗展示的是当前应用界面的UI控件树,类似于浏览器里的开发者工具。你可以看到一个层次分明的结构,里面包含了每个控件的名称、类型、坐标、文本内容等属性。你可以点击树上的任何一个节点,手机上对应的UI元素会高亮显示。这个功能对于编写脚本太有用了,你不再需要靠猜和反复截图来定位元素。
### 4.2 编写基于Poco的精准操作脚本
假设我们要测试一个新闻App,需要自动点击第一条新闻的标题进入详情页。用图像识别的话,你需要截取新闻标题的图,但新闻内容是会变的,截图方法就失效了。用Poco,我们可以这样做:
在Poco辅助窗的控件树里,找到代表第一条新闻标题的那个控件节点。通常它是一个TextView或者类似的东西,会有text属性显示标题文字。我们可以用多种方式定位它:
- 通过属性选择器:如果这个标题控件有唯一的
name或text,代码可以这样写:# 假设控件的name是“news_title_1” poco(“news_title_1”).click() # 或者通过文本内容来定位 poco(text=“今日头条:AI技术新突破”).click() - 通过层级关系:如果控件没有唯一属性,可以通过父子关系来定位。
# 先定位到新闻列表(可能是一个ListView),再取它的第一个子元素 news_list = poco(“android.widget.ListView”) first_news = news_list.child()[0] # 获取第一个子控件 first_news.click()
Poco的click()方法和Airtest的touch()效果一样,但原理不同,它是直接调用系统底层的控件点击接口,速度更快,且不受界面颜色、特效的影响。你还可以做更多事情,比如swipe()滑动列表,get_text()获取控件文本进行断言验证,set_text()输入文字等等。将Airtest的图像识别和Poco的控件识别结合使用,一个负责处理“不好定位”的图形部分(比如游戏内的3D场景操作),一个负责处理“结构清晰”的UI部分,这样构建出来的自动化脚本既健壮又高效。
5. 真实项目案例:如何用Airtest为游戏自动化测试提效
纸上谈兵终觉浅,我来分享一个我们团队的真实案例,看看Airtest是如何在游戏测试中落地并发挥巨大价值的。我们当时负责一款中度休闲手游的测试,这款游戏有几十个关卡,每个关卡需要测试通关流程、技能释放、怪物刷新、奖励结算等。手动测试一轮需要一个人天,每次版本回归都是噩梦。
### 5.1 需求分析与脚本规划
我们首先分析了测试痛点:重复性高(每个关卡基础流程相同)、覆盖面要求广(所有关卡)、稳定性要求高(不能漏测)。我们决定为游戏的核心战斗流程设计自动化脚本。脚本的规划如下:
- 启动与登录:用Airtest图像识别点击“开始游戏”按钮,处理可能的更新弹窗。
- 选择关卡:进入关卡选择界面。这里UI是固定的,我们使用Poco来精准点击指定关卡(如“关卡1-5”)。
- 战斗过程:这是最复杂的部分。因为战斗场景是动态的3D画面,UI控件很少,我们主要依赖Airtest图像识别。
- 识别并点击屏幕上的“开始战斗”按钮。
- 识别英雄头像,周期性点击释放技能(通过循环和
wait()语句实现)。 - 识别“胜利”或“失败”的标志弹窗,作为战斗结束的判断依据。
- 奖励结算:战斗结束后,会弹出奖励界面。我们用Airtest识别“领取”按钮并点击,然后识别是否返回主界面,完成一个循环。
### 5.2 脚本实现与关键代码
在战斗环节,我们遇到了挑战:技能图标在冷却时是灰度的,图像识别容易失败。我们的解决方案是,同时准备两张图:一张是亮色的技能图标(可用状态),一张是灰色的技能图标(冷却状态)。在脚本中,我们优先尝试点击亮色图标,如果找不到(相似度低于阈值),就等待一小段时间,然后继续尝试,而不是直接报错。这模拟了真人等待技能冷却的行为。
# 伪代码示例:释放技能的逻辑
def cast_skill():
# 尝试查找亮色的技能图标
if exists(Template(“skill_active.png”)):
touch(“skill_active.png”) # 找到并点击
log(“技能释放成功”)
else:
# 如果没找到亮色图标,可能是冷却中,等待0.5秒再循环检查
log(“技能冷却中,等待...”)
sleep(0.5)
对于奖励结算的弹窗,我们使用了wait()函数,它会等待某个图片出现,并设置一个超时时间,避免脚本因为网络延迟等原因卡死。
# 等待胜利标志出现,最多等10秒
victory_popup = wait(Template(“victory.png”), timeout=10)
if victory_popup:
touch(victory_popup) # 点击胜利弹窗的任何位置,通常可以关闭它
else:
log(“战斗可能未胜利或超时”)
# 这里可以加入失败处理逻辑,比如重试或记录错误
### 5.3 效果与收益
通过编写大约20个这样的关卡自动化脚本,我们将核心关卡的回归测试时间从8人小时压缩到了1机器小时。测试人员只需要在版本更新后,跑一遍自动化脚本,就能快速验证核心功能是否被破坏,从而将精力投入到更重要的新功能测试和探索性测试中。脚本运行过程中产生的截图和日志,也成为了问题定位的宝贵资料。这个案例告诉我们,Airtest不是要完全取代人工测试,而是把测试人员从重复、枯燥的劳动中解放出来,去做更有价值、更需要人类智能的判断工作。
6. 避坑指南:Airtest实战中常见的“坑”与解决方案
用了这么多年Airtest,踩过的坑数不胜数。把这些经验分享出来,希望能帮你少走弯路。
### 6.1 图像识别不稳定怎么办?
这是新手最常遇到的问题。明明昨天还能跑通的脚本,今天怎么就找不到按钮了?可能的原因和解决办法如下:
- 画面变化:游戏换了皮肤、App改了主题色。这是最根本的冲突。解决方案:尽量使用UI中稳定不变的部分作为截图模板。比如,截取按钮的图标部分而不是整个带背景的按钮;避免截取带有动态光效或颜色渐变剧烈的区域。如果UI确实经常变,那就要考虑和开发团队约定,为自动化测试保留一些稳定的测试标识,或者转向使用Poco控件识别。
- 分辨率与缩放:在不同分辨率的设备上运行脚本。解决方案:Airtest的图像识别本身支持一定程度的尺度缩放,但并不完美。最佳实践是建立基准设备,所有截图模板都在同一台基准设备上截取。运行脚本时,Airtest会尝试进行缩放匹配。你也可以使用
resolution参数进行手动适配。 - 相似度阈值:默认的阈值(通常是0.8)可能不适合所有情况。解决方案:在
touch()或exists()函数中,调整threshold参数。对于清晰、稳定的图标,可以调高到0.9以上以提高精度;对于容易变化的图形,可以适当降低到0.7甚至0.6。但调太低会增加误触风险,需要平衡。 - 多图查找与等待:不要指望一次
touch就能100%成功。解决方案:使用wait()函数代替直接的touch,给它一个寻找和等待的时间。或者使用exists()判断是否存在,如果不存在则执行一些备用操作(比如先滑动一下屏幕再找)。
### 6.2 脚本如何在多台设备上运行?
你在一台1080P的手机上开发的脚本,怎么让它在公司测试部门的十几台不同型号的手机上都能跑?硬编码屏幕坐标肯定是死路一条。
- 使用相对坐标或百分比:Airtest提供的
Touch操作虽然主要用图像识别,但也支持坐标。但请不要用绝对坐标。如果非要用坐标,请使用基于屏幕分辨率的相对坐标。例如,要点击屏幕中央,可以用touch([0.5, 0.5]),这里的0.5代表屏幕宽度和高度的50%。 - 设备集群与云测试:网易官方提供了 AirLab 云测试平台,你可以将脚本上传,在云端海量的真实手机设备上并发执行,自动生成兼容性测试报告。对于大型团队,他们甚至提供了私有化手机集群技术方案,可以把这套云测环境部署到公司内网,使用公司自己的测试机群,保障测试数据的安全。这对于需要覆盖大量机型的游戏和App来说,是提升测试效率的终极方案。
- 脚本参数化:将设备信息、应用包名等配置项提取到单独的配置文件中。运行脚本时,通过命令行参数或配置文件来指定当前运行的设备。这样一套脚本就能灵活适配不同环境。
### 6.3 如何组织和管理大量的测试脚本?
当你的自动化脚本越来越多,你会发现它们变得难以维护。脚本之间如何复用?公共操作(比如登录)怎么抽象?测试报告怎么统一查看?
- 模块化与函数封装:这是软件工程的基本思想。把通用的操作封装成函数,比如
login()、logout()、enter_level(level_num)。每个具体的测试用例脚本,去调用这些公共函数。这样,当登录流程改变时,你只需要修改login()函数一处。 - 使用测试框架:Airtest脚本本质上是Python代码,你可以用
unittest或pytest这样的Python测试框架来组织你的用例。这样你可以利用框架的setUp/tearDown(初始化/清理)机制、断言方法,以及强大的测试报告和用例发现功能。 - 版本控制:一定要用Git等工具管理你的自动化脚本代码。这能方便地回溯历史、协同开发,并且与你的被测应用版本关联起来。
- 持续集成:将你的自动化测试脚本集成到Jenkins、GitLab CI等持续集成工具中。每次开发提交代码,或者每晚定时,自动触发测试脚本的执行,并及时将测试结果反馈给团队。这才是自动化测试价值最大化的体现。
记住,引入自动化测试是一个过程,不要期望一蹴而就。从最重要的、最稳定的一个用例开始,慢慢积累,逐步构建起你的自动化测试体系。Airtest是一个强大的起点工具,它能让你快速看到成效,建立信心,然后再向更工程化、体系化的方向迈进。
更多推荐
所有评论(0)