接触Sonic也快小半年的时间了,一直想写点东西总结下。正好最近Sonic社区举办活动征集大家的技术分享,借此机会也蹭个热度。
背景
团队内一直对UI自动化比较重视,之前自己基于Cucumer + Appium Client的方案实现了一套自动化测试框架,在团队内也大范围使用落地推广。和Sonic的结缘其实也非常偶然,有一天在testerhome上发现了这个宝藏工具,一通操作部署体验后感觉各方面都很优秀,于是也开启了对sonic的深入探索研究。
Sonic的使用心得
(1) 用例编写体验
可以说是Soinc一开始最吸引人的一点了:
(1) 做到屏幕左侧实时投屏设备,右边拖拽式生成用例步骤,快速调试运行。
(2) 远控页面,可以直接dump出视图树结构,并点选元素,添加到元素表中。之前使用Appium的时候,都是通过desktop工具去复制属性,然后粘贴到IDEA工程中,对比下来很繁琐。
并且Soinc在iOS上dump视图结构的速度比Appium desktop 要快很多,启动wda也明显快了不少,具体原理还没深入研究,不过还是要先给作者点赞。
(3) 远控界面,具备通过Web端操作手机屏幕的能力,并且还提供了应用程序操作,网络抓包等能力,非常强大。基本做自动化用例的编写,已经完全不用手动的操作手机,直接在web网页上全搞定。
不过目前用例编写体验上,也有些优化的建议和想法:
(1) 步骤的复制每次都是默认加到了最后一条,当用例非常长的时候,再拖拽到预期的位置还是很麻烦的,如果能复制到任意行就好了;
(2) 没法批量的复制,删除,移动多个步骤(不过感觉实现上也挺困难,毕竟不是纯文本的IDE环境);
(3) 可以考虑从指定某一步开始运行,这样在修复验证用例的时候,能节约不少时间。
(2) 用例的组织结构
Sonic提供的用例编写,用步骤的方式来进行组织,使用者可以通过步骤操作面板,点选自己需要的操作。真正做到了傻瓜式无门槛,不需要任何编程经验,相对于Appium,Airtest这类有脚本的框架来说,非常的便捷。而且公共步骤和全局变量等进阶的能力,也提供了非常大的灵活性,甚至还直接内置了执行脚本的能力。
不过对于之前经常使用JUnit,PyTest这类框架的同学来说,没有setUp,tearDown会比较不适应。
(3) 测试套件的使用
对于希望大范围落地UI自动化测试的团队,CICD是非常重要的能力。sonic在这方面也提供了很好的支持,社区内这半年也看到了不少新功能的开发。
个人的一些建议与想法:
(1) 需要有用例重试的能力,其实做过UI自动化的同学都有一个切身体会,就是UI自动化用例本身非常“脆弱”,经常会发现用例的失败并不是产品的问题,而是自己用例的问题=。= 用例重试其实是个屡试不爽的办法。
(2) 用例选择上,目前的点选体验还是有些麻烦,并且没有按模块筛选的能力。其实之前用cucumber的时候,tag表达式是一个非常亮眼的能力。


通过@Android and @Base
就可以筛选到用例1,通过@Android
就可以同时筛选到用例1和用例2,在用例数量比较多的时候,非常方便。只需要关注每个用例增加哪些tag就可以了。
(3) 设备选择上,感觉只需要提供一个设备数量即可,在分发的时候自动选择出空闲的设备,调度执行用例即可。
(4) 测试结果报告,Sonic同时提供了测试运行日志,性能采集,录像(还未放出)。不过之前自己的项目中采用的是自建Allure服务器的方式来做最终的报告展示,

感觉Allure的结果筛选,单用例的历史记录(可以非常好的用来分析用例不稳定的原因)等功能都非常的好用。后续Soinc的结果报告也可以考虑尝试与Allure来进行结合。
基于Sonic二次开发尝试的一些功能点
(1) 支持用例同时运行安卓与iOS双端
同一个产品,在Android和iOS端,其实基本的UI和功能都是一致的,因此用例能同时运行在Android和iOS双端是个非常明显的优势。这里也尝试对Sonic作了比较大的二次开发改造。变更最大的是element表,按照Sonic的设计。element表中只有一个ele_type和ele_value字段存储了元素的定位方式和定位值。为了支持跨端,单独搞了一个ele_location表,与element表相关联,一个element表中的字段,在ele_location表存在多个与之关联的记录。

上表中即可看到同一个ele_id,在ele_location表有不同端的定位方式记录。

增加元素的界面UI如上。
其实单独抽取ele_location表的原因,一开始是希望一个元素能同时指定多个查找方式,比如根据resoure_id失败后,再根据xpath来查找。实际用下来发现这样的设计有些过度,因为第一个定位方式失败,大概率第二个也会失败,反而增加了元素表的维护成本。
因此回过头来看,支持跨端,其实更好的方式可能是直接基于element表增加列,指定不同平台下的不同定位方式和定位值即可。
(2) 元素查找方式的一个优化
Sonic一开始的设计,是每一个需要被操作的元素,均需要在测试数据管理->控件元素,增加一个记录。使用上感觉还是有些不太方便,这里做了一个增强,新增加了两种:

文本的方式,底层会根据传入的文本,拼接出一个xpath和classChaind表达式,分平台进行查找。

协议的方式主要针对web端,直接输入定位方式+定位值即可。
两种方式的效果如下:

步骤3中的“取消”就是个纯文本的定位方式,底层框架会尝试找到文本为“取消”的控件,并做点击。
步骤4中的“cssSelector/.cancel”是协议定位的方式,底层框架会通过css选择器值为.cancel的方式去查找,并做点击。
使用下来的体验看,纯文本的定位方式非常的方便灵活,尤其是针对固定文本的场景,可以省去单独录入元素这个步骤。协议定位的方式就比较有争议了,因为有时候很难知道当前的这个css选择器代表的是什么元素,给后续的维护带了成本。
(3) Agent端与被测App端建立GRPC通道,实现自动化控制App的高级指令
做过Appium这类自动化的同学应该有一个体会,就是自动化框架自身对被测App提供的都是一些通用的能力。有时候我们期望有一些更高级的指令,提供给自动化框架来调用。比如说,通过自动化测试框架,触发App执行一个特定的router跳转等。建立GRPC通道就是为了实现这个定制化的能力。
目前我们的方案,是Sonic Agent内充当GRPC Server,被测App充当GRPC Client。在Sonic Agent中预埋了一些特定的指令,允许上层的UI自动化步骤调用,在被测App内,通过一定的侵入业务逻辑的代码,来响应这些指令。当前支持了如下几个比较有特色的能力:
(1) 做数据mock,脚本层需要指定url和期望这个url返回的数据内容,App收到这个数据mock指令后,在网络库中做拦截,一旦发现App触发了指定的url的相关请求,则直接返回GRPC Server期望返回的数据内容即可。这样可以验证同一个UI界面,在不同数据返回的情况下,具体的页面表现行为。
(2) 触发登录(模拟),App的很多功能都需要登录态,如果走真实的登录流程还需要拉起来微信或者QQ,很耗时且容易失败,这里我们找后台开了几个白名单账号openid,通过指令直接让App自动获取登录态,省了很多事儿~
(3) 执行router跳转,App中的很多页面都支持Router的方式打开,在上层的脚本,可以直接指定要打开的页面的路由地址, App就可以快速打开对应的页面,避免了一些入口深的场景前置步骤太繁琐。
(4) 尝试支持iOS端的Web上下文切换
Sonic目前只支持了在安卓上,进行web上下文的切换,iOS上还不具备这个能力。这里我们用了一个比较绕的方式,写了一个Node的服务,基于appium-xcuitest-driver提供相关的自动化接口能力,同时在SonicDriver Core中封装了相关的方法与自建的Node的服务来通信,并将相关的接口返回给Agent。目前做到了对齐Android端的Web上下文切换能力。
不过目前看这个方案也有一些不足,与Android端的基于chromeDriver的代码没有进一步的封装,存在很多冗余的代码。并且在windows上也无法支持,仅使用Mac端。
(5) 用例标签能力

用例标签的能力其实相对比较简单,可以理解为就是允许标记一个用例同时属于多个模块。标签最大的作用,是为了实现用例的筛选,通过一个标签表达式语法,来筛选中需要运行的用例。
结语
零零碎碎的写了一些,算是对自己最近小半年工作的一个总结。另外也给Sonic打一波广告,真的非常强大,并且社区活跃度很高。也提前预祝Sonic组织在MTSC分享顺利。