@qinyun
2017-11-03T16:37:09.000000Z
字数 9002
阅读 2307
未分类
嘉宾简介:
洪至远,百度高级测试开发工程师,百度 MTC-Android 自动化测试业务负责人,从零开始设计并实现了 SmartMonkey、混合脚本测试服务、录制回放工具等。主要专注于 Android 自动化测试工具和框架方面开发。本文为洪至远在2017QCon.上海的演讲内容。
MTC 是一个面向开发者的移动测试平台,专注于为开发者提供一站式的 App 测试服务,随着业务的不断增长,我们迫切需要一套通用的、可以适用各类场景的脚本测试解决方案,但是传统的脚本测试框架如 UiAutomator、Robotium、Appium 都各有弊端,单一的测试框架无法满足我们的需求,因此,混合脚本测试解决方案应运而生。此次将向大家分享我们在设计、开发混合脚本测试框架及对应的脚本录制工具中碰到的一些问题和解决方案。
我们为什么要自动化测试?优点有很多,我列了三个。
一,缩短测试周期。当前我们产品迭代速度非常快,我们经常会经历一些回归测试等相关测试,这些测试里面需要人力手工执行许多重复化的case,这些case人力执行起来很慢,通过自动化测试,可以任意时间跑一些脚本,可以全天候跑测试,缩短测试周期。
二,统一标准,避免人为出错。如果测试是强依赖于人工,人工难免有各种各样的错误,难免会出错。比如我写测试脚本,忘了某一个case脚本,忘了执行某一个case,如果用自动化测试,完全可以把这些问题避免掉。
三,提升测试的覆盖率,安卓测试中碰到一些APP需要覆盖到各种各样的手机机型,如果依赖于人工,很难做到这个层面的覆盖。如果自动化测试,一套脚本可在多款机型上执行,提升测试的覆盖率,并提早发现一些很难发现的问题。
一个常规的自动化测试场景,一般情况下测试人员接到一个case,我们会根据这个case编写脚本,脚本我们会通过一些ID工具编写脚本,并且在本地测试。测试OK之后,我们会把这个脚本通过测试平台,这里的测试平台泛指把脚本下发下去之后,在很多机器上执行的平台。通过这种平台,可以让我们脚本自动化地执行,并且可以覆盖多个手机,在平台上执行之后可以收集到结果。但过程中很可能脚本执行有些意外情况,这时我们就要把脚本拿回来再重新改,再兼容,有一个循环的过程,保证我们的脚本可以正常执行,可以正常地发现一些问题。
但是这个场景里面我们会碰到几个比较重要的问题。首先我们编辑脚本我们需要选择一个合适的测试框架,另外我们下发脚本下发到平台上测试,也会面临到一个脚本的兼容性问题。
我们怎么选择测试框架的?我列了几个常见的测试框架,appium、Robotium、UIAutomator这几个也是我们方案过程中比较常用的框架,大致地做一下对比。
首先讲一下Robotium,这是一个很好的框架,可以进行黑盒测试,并且对控件识别做得比较好,而且有一套插装机制,可以实现其他的自动化测试。它原生上不支持跨进程,这个缺点很致命,如果要测APP,需要对APP进行重签名,如果APP是加固的,或者有防重签名的措施在里面,会导致你这个测试无法进行下去。所以这两个缺点对我们来说都是比较致命的,虽然说Robotium也有一些对应的外部跨境方案,但相对来说并不是很理想。
第二个是Appium,这个框架确实做得十分优秀,本身支持跨平台,安卓、iOS都可以支持,而且支持的安卓版本十分全面,高版本、低版本都有各种方法解决。而且配备的开源社区十分活跃,如果碰到任何问题,都可以很快地找到一些解决方案。但也有一个致命缺点,稳定性不足,相当于你在传统测试脚本框架基础上做了一些额外的分装,有各种中间件,而且整个架构相对来说比较臃肿,对我们测试场景来说不是很适合。因为我们需要把一个脚本下发到很多的手机上去批量执行。如果有一丝的稳定性问题,导致测试结果相对较差,会更加把稳定性问题暴露出来,单台测试是看不出来的。因为稳定性不足的问题,被我们pass掉了。
最后是UIAutomator,是谷歌的亲儿子了,是谷歌开发的框架,本身也有很多优点。首先它是原生的,是非嵌入式机制,可以进行黑盒测试,有一个很优越的特制就是支持跨进程。我们很多方案都是基于UIAutomator的跨进程去做,而且运行起来十分稳定,对原生控件获取十分好,但UIAutomator本身不支持安卓4.1以下系统,对非原生界面支持较差。它对我们来说没有致命性的问题让我们放弃它,最终我们选择的,我们用的最多的还是UIAutomator。
选择完之后测试流程上还是会碰到很多问题:
第一,测试脚本放下去之后执行过程中会受到各种各样的干扰;
第二,我们现在的测试框架对非Native场景支持都比较差。
第三,就是如何提升效率的问题,人工编写脚本比较耗时。
首先讲一下执行干扰问题。最常见的就是权限的弹窗干扰,跑着跑着突然发现断了或者跑着跑着出现一个干扰之类的,脚本就挂掉了,这种问题十分常见。而且脚本如果步骤很长,任何一步出现问题,就导致整个脚本出现问题,所以这对我们来说是比较严重的一个问题。
运行过程当中主要解决的是弹窗干扰,我们提到的测试系统,对你的测试脚本执行的干扰,这些都自己针对自己的本地系统,做一些相对优化,防止系统对脚本进行干扰,还有测试过程中手机上对脚本的干扰,弹窗干扰主要碰到的有两点,进程内和进程外的弹窗。
权限弹窗是APP之外的弹窗,它并不是在APP进程之内的,有一些系统更新等外部APP的弹窗,也会导致你这个脚本执行会有问题。
第二个是进程内的弹窗,比如摩拜,跑着跑着弹一个窗出来,导致你后面的脚本会出现一些问题,所以主要就是解决这两块。
进程内弹窗完全可以通过脚本逻辑清理掉,你可以在脚本执行过程中在UIAutomator基础上做一套封装,去看看是否有弹窗逻辑,把进程内的弹窗直接清理掉。
进程外的弹窗需要通过夹杂方案,比如通过UIAutomator,跨进程操作就很好地帮我们解决了这个问题,它可以进行跨境操作,这样进程外的操作可以直接通过UIAutomator给识别,并且点击掉。
一个APP执行过程中,界面可以理解为很多层,如果有一个弹窗,弹窗单个是一层,它会被系统化,它有很多漏洞组成,你能根据上面元素上的节点,就可以发现我当前的APP已经被其他的东西被干扰掉了,这时候是一个潜在的弹窗可能性,你就可以做些弹窗的清理工作,或者是你APP自身的恢复工作。
定位弹窗是比较Low的方案,UIAutomator自身就可以基于元素的方案和文本的方案。基于元素就是基于系统,一套方案可以解决根本的问题。其实国内有各种各样的定制,把系统的UI各种更改,所以会出现各种奇怪的弹窗,有各种各样的构造,所以基于元素的方案很难去做。
但我们看到那么多弹窗问题之后,发现他们的文本相对来说比较简单,他们是基于文本去匹配,文本不多,主要是那几种类型的允许、确定之类的东西,比较固定,不同的Room都差不多,所以后来我们基于文本的方式去匹配,针对性地对弹窗进行分类,针对性地把弹窗给点击掉,这就是我们后来综合考虑之后采取的一种方案。
后来我们在UIAutomator的基础上做了一套清道夫的SDK,方便我们把弹窗的操作清理掉,保证我们脚本之间的稳定性。随后我们会在那个基础上加了其他的封装,因为我们发现那个脚本执行过程中除了弹窗之外还有很多其他的稳定性问题,比如UIAutomator你跑一百步、两百步的测试case,会在第80多个的时候,点击某一个元素,这种问题在测试case比较多的情况下,容易发现这个问题。
经过一次重试,我们就在清道夫SDK里面加了操作的记忆功能,如果操作出现异常情况下会加一些重试,保证每个操作都能够正常进行。增加自定义截图功能支持点击位置展示。我们后面所有基于UIAutomator的测试方案,都是直接通过清道夫SDK,把API暴露出来,直接通过它的API去做一些自动化测试,就可以从底层去支持我们脚本的稳定性方案,让我们脚本变得更加稳定。
解决了脚本稳定性之后,我们还面临一个比较大的问题,非Native场景的支持。
提到非Native场景,哪些场景支持会比较差?我们提的最多的,也是我们最头大的测试场景,现在因为这种APP的模式确实比较有优势,它可以很快地更新,开发起来会比较快,如果你这个操作对体验要求并不是很高的话,用WebView可以,但我们测试起来非常麻烦。有很多外层的东西你识别不到,其实相当麻烦。
第二个问题场景就是游戏,游戏也是一个很大的测试类型,界面通过游戏已经渲染出来你看到的都是整个一张大图,所以你很难进行一些元素的识别,这对我们来说也是比较棘手的一个场景。
第三个问题是PopupWindow,像这种安全键盘,其实是一个PopupWindow,页面基础上加了一层Window,识别过程中焦点根本不在安全键盘上,导致安全键盘元素根本识别不到,这样你就很难做元素的获取,去进行点击之类的操作,所以这也是一个比较大的问题。
对应的解决方案,首先是基于元素方案解决问题,比如ChromeDriver来进行元素解析,进行分装再进行操作,其实也有赖于版本的问题,有一些WebView死活有一些元素识别不到,稳定性上面也不是很好。游戏的话通过嵌入SDK,针对引擎特点反射UI控件元素,这个也差不多,通过游戏引擎,可以把游戏上的元素一个一个发现。是一个方案,但需要嵌入SDK,这是嵌入式操作,相对来说并不是很可行。
PopupWindow通过代码层可以解决这些问题,有了弹窗之后加入Focus,我们的WebView就可以识别了,这也是依赖于原码。
基于元素这一套方案,并不是很可靠,它都有一些缺点,而且都挺致命的,会让我们这个东西就没办法进行下去。
还有另外一套方案,图像识别方案,这是现在比较流行的一套方案,游戏一些测试很多都是基于图像识别去做,原理操作上很简单,每个测试流程中一开始是输入一些元素的图标,每次操作都通过把元素图像和实时截图做对比,拿到一些对应的元素位置,通过adb可以对其进行元素操作,这是一个完整的测试流程。其实它也有很多优点,它完全黑盒,而且你根本不需要Care你这个测试在什么上面跑,只要能进行图像识别,能跑这个服务就OK了。所以跨平台是非嵌入式,这套方案相对来说比刚刚那套基于元素的方案,优点很明显。相对来说它比较稳定,而且它的普适性比较高。
下面简单对两种方案做一个对比,我们也主要参考三个方面。主要是稳定性、易用型、准确性。稳定性就是跑起来会不会出现这种不支持那种不支持?这就定位为稳定性问题,元素的方案就并不是很好。易用性就是我们可不可以通过一套方案解决?基于元素的方案也不一样,需要你针对各个场景都有各个不同的解决方案,所以易用性上也不是很好。虽然这两点不是很好,但基于元素的方案准确性比较好,虽然准确性好,但这个优点并不足以让我们选择这个方案,所以我们最终还是选择了图像识别的方案,因为各项来说都还可以。
提到图像识别方案就不得不提到匹配算法,匹配算法很重要。
常见的就是两种算法,模板匹配算法,优势是速度快、算法简单,相当于你把元素图标直接到原图上一个像素一个像素地比对,算出一个全值,找到最优的位置。这种方案随着确实比较快,而且算法速度快,算法简单。劣势是容易受到干扰。
我们针对干扰可以用到特征点匹配算法,基于特征点,精度高,抗干扰能力强,你旋转、拉伸都无所谓,但劣势是速度慢,简单图形匹配精度不高。
这两种算法其实是优势互补的,所以他们两者可以进行一个相应的互补,我们可以把这两种方法结合起来做一个整合测试。
刚刚说到的那两种算法都有一个共同的问题,他们对于简单的图形识别并不是很好,虽然匹配的算法可以识别简单的东西,但如果你屏幕拉伸,其实影响会比较大,针对于这一些场景,文字、字母的简单场景,我们又基于ACR方案,针对图像提取对应的文字信息,主要用途不是这个,但我们可以依赖于这套特性做事情。文字可以直接通过OCR知道对应的位置,我们就可以把它当做一个识别方案,进行一个识别,来解决我们这方面的bed case。
其实我们最终整合了这几种方案,一个模板匹配算法,一个特征点算法,一个OCR,整合了这几点方案之后,整合到一起,变成一整到工程化解决方案,可以对各种场景做到更好的支持。即使如此,在测试过程中仍然会碰到各种各样的问题,比如分辨率问题,模板不行,特征点也不行,这种情况下分辨率导致了OCR识别不了,我们通过在测试过程中做些自动匹配,提升我们模板算法的适用性,来尽量地让我们整个一套方案变得可行。
另外我们可以限定匹配区域,提高匹配准确度。整个屏幕上有很多干扰性图片,我们如果稍微限定一下匹配区域,其实会很大程度上提高我们的匹配度。我们用这套方案解决整个图像识别的匹配过程,我们平时自己做下来,大概能达到99%点几的匹配程度率,可以达到让我们整个匹配变得可行。
元素识别和图像识别,现在就是两套方案。基于UIAutomator,做一些对Native场景的支持,利用图像识别测试主要做非Native的场景支持。UIAutomator对延伸场景支持的非常好,有很多的优点,图像识别也有各种各样的优点,算法成熟,对非Native场景来说比较好。如果把两者结合起来,能比较好地看到我们日常碰到大部分的测试场景。所以最终我们考虑把这两种方案结合起来,互为补充。
我们如何结合这两种方案的?图像识别一开始跑在PC端,因为PC端相对来说比较方便,你如果要结合,就把它们放在一起,通过KPI把它暴露出来,将图像识别能力迁移至手机端,在手机上跑图像识别,将UIAutomator迁移至PC端,有成熟解决方案。
测试过程当中我们发现,图像识别相对来说比较耗CPU,会对你整个测试过程中的性能数据产生一定的影响,所以这套方案考虑一下就把它pass掉了。把UIAutomator迁移到PC端,有很多套方案,综合考核之后我们还是选择第二种解决方案,把UIAutomator迁移到PC端。
还有我们整个混合脚本测试解决方案,PC端是统一的API,其实也是把这两种服务给结合起来。图像相关的一些操作就直接在PC端上执行完就OK了,元素识别相当于我们会把所有的操作进行封装,我们设备端会写一个空的测试脚本,主要是暴露http sever服务,通过APP可以进行很直接的访问。在PC端的访问封装之后,发送到设备端,设备端对操作进行一些解析,再走到清道夫SDK,再到UIAutomator,做到整个一套设备端元素识别的操作,再发回给我们。
最终这样看下来,在PC端通过一套API,我们把两种服务都给结合起来,对测试人员来说完全无感知,这样可以很好地解决各类场景中的问题。
总结一下,有几点。首先我们是对UIAutomator进行封装,提升脚本的稳定性。综合使用各种图像识别技术,覆盖了非Native场景下的测试,通过整合API,通过写一套脚本覆盖各类场景的测试,这就是最终我们混合脚本测试解决方案,这样可以很好地解决了我们之前提到的几个问题。
有了这样一套方案之后还是会出现一些问题,比如脚本编写还是需要人工去做,这主要就是提升效率的问题了,还不是我们碰到的根本难点问题,所以这块很容易想到的就是搞一个录制工具,通过一个录制工具把脚本都记下来,自动生成脚本,可以大大提升效率。录制工具就是一个界面,我们可以通过一些简单的点击操作,自动识别生成测试代码,如果你最后OK了,生成最终脚本。因为整个测试解决方案是一套API,让我们测试工具变得可行,通过生成一套脚本,就可以覆盖各种各样场景。所以我们前面准备工作也是为了我们录制工具的顺利进行。
核心功能包括几块。手机屏幕展示,手机操作功能,根据操作生成脚本(难点),主要就是这三块。对于安卓来说并不复杂,安卓手机屏幕展示直接通过开源的Mini cape(音)就可以做到。
手机操作可以通过APP的操作,就可以对手机进行操作,这些都很成熟了,也都很简单。比较难的就是怎么根据操作生成脚本呢?这块你需要有一定的逻辑在里面,因为这也是我们整个录制工具比较核心的一块。
然后我们也有几个比较现成的方案,比如录制工具,怎么识别脚本?我们基于坐标方案,直接点一下这个坐标,我们点一下就有生成这个坐标的脚本,劣势是受到分辨率的影响很大,通常脚本会发到500款、600款的手机长跑,坐标的范围劣势很大。
基于元素出行的方案比较简单,通用性更好,基于元素不会受到分辨率的影响,可以直接查找元素,这样通用性相对来说比较好。如果你点击元素之后,元素属性也不唯一,你碰到一个列表,列表里面有很多的部分,每个部分都有很多元素,元属性不唯一,导致你可能会找不到这个元素。所以这两种方案都有一定的劣势,但很明显,第一种方案可以直接被pass掉,因为劣势太大了。所以我们可以基于第二种方案的基础上做些改良。
最终我们通过点击路径的方案去做。本身一个界面是一个界面树,是一个树形结构,我们可以把手机界面拉取过来,每一次点击可以从点击位置开始往根节点回溯,记录我们的路径,路径唯一确定了这个元素之后,这条路基本上就是我们最终生成的脚本,封装起来之后我们可以对它进行操作,可以唯一定位我们这个元素。
录制工具整体解决方案,首先分成几块。安卓设备、录制工具服务端、前端界面。主要工作就在服务端这边做,前端界面包括操作的模块,图像展示、代码生成这都是服务端上的。服务端主要提供几个功能,界面解析,生成对应的元素路径,前端界面通过点击操作过来之后,我们根据Dom树结构拿到元素路径,生成为一的代码,返回到前端这边,前端拿到现成代码,把脚本编一下执行下来。基于adb都有现成的好的方案可以去做,其实没有困难,相对来说可以很好地去解决。
整合刚刚所说,我们整个自动化测试解决方案,现在整个方案变得比较简单,可以直接基于我们的录制工具,一个比较通用的脚本,可以在我们机器上比较稳定地运行,可以覆盖比较全面地去跑。我们录制完这个脚本之后,可以直接在我们平台上下发,MTC这个平台总共有1千多台真机,通过我们平台下发,可以稳定地执行,可以实现覆盖,最后通过查看测试报告,整个就是我们平时工作中的自动化测试解决方案,就是这样一套流程。
Q1:你好,我想请问一下,你刚刚提到前端会有一个测试脚本,那你们这个测试脚本app服务你们怎么实现这个部分的?前端执行的一套脚本,调用清道夫SDK,你们怎么实现这个前端功能?前端测试脚本你们是怎么做到的?
洪至远:其实核心点在于PC端跑些UIAutomator的操作,在手机端跑一个测试脚本,你可以写个SDP服务(音),在手机端可以通过端连设备(音),进行一些访问,可以解析,服务对服务。
Q2:对于混合应用来说,通过图像识别,识别的元素可以点击一些操作,对于一些输入框的元素,这样不仅仅是点击,其实还有对文本输入,包括文本是数字、英文,特殊字符还有中文,这个问题你们是怎么解决的?
洪至远:基于元素,核心首先第一步肯定是要点的,我们用图像识别,输入框之类的首先第一步能点到它,我们在图像这边会把几个操作合并起来,你点击它输入名字,输入名字可以通过APP的方法,也有一些开源解决输入中文问题的对应的解决方案,其实综合起来就是通过图像识别找到元素,通过点击进行APP收入。
Q3:通过图像识别文本框,对应的特性是比较少的,我不知道识别的方案是什么?你是通过参考元素?还是通过识别文本框?因为有很多文本框就是一个空白。
洪至远:对,文本框识别精度上比较难,基于特征点很难找到,更多可以基于模板匹配,模板匹配比较容易找到文本框。我们后来把区域给限定,区域限定之后,你相对来说查找起来更加方便,因为模板的方法最大的问题是在于分辨率的问题,多个分辨率下会有影响。所以我们后来针对不同分辨率去做了不同分辨率下的截图,自动去匹配,通过这个来匹配模板,因为模板除了分辨率也受到其他的干扰,旋转类的干扰,这在手机上很难碰到,手机上都是比较困难的图像,所以主要是分辨率的影响,最后我们会对分辨率做一些单独的试配,拿不同分辨率下的截图自动去匹配。文本框我们目前主要是基于模板匹配,效果也还可以。
Q4:你好我想请问一下,在百度图像识别的测试方法现在应用的多不多?够不够成熟?你们用图像识别进行测试的时候,一套完整的标准是什么?比如我如何知道测试结果是正确的,或者是错误的?如何成为一个替代UIAutomator的?图像识别越来越精准,或者更加成熟的话,会把更多脚本的测试方案给替代。
洪至远:目前来看,我们整个测试过程中,比如我们平时有各种各样的测试任务,拿一个最简单的,跑一个测试APP,有一百步的测试过程,用到图像识别的在十来个左右,十分之一多一点的覆盖率。Native场景居多,优点是图像达不到,准确率确实比图像高太多。图像有99%的成功率,但你,有一百步,0.99的100次方就是0.5以下了,很多步之后,准确率会越来越低,是一个指数性的东西。所以图像识别对我们来说更多是一个替代的方法,不能作为主要的测试方案,我们这边更多的是Native覆盖不了的场景我们用图像识别,不是能进行替代,主要是作为补充。
https://developer.android.com/training/testing/ui-automator.html
https://en.wikipedia.org/wiki/Scale-invariant_feature_transform
https://en.wikipedia.org/wiki/Speeded_up_robust_features