SmartMonkey--UI遍历

来源:互联网 发布:厦门云智盛世 数据库 编辑:程序博客网 时间:2024/06/07 01:16
前言


业界常用Android SDK中的Monkey长时间频繁快速的对app界面进行各种操作,从而检测app的稳定性,辅助手工测试人员发现不易发现的问题。然而,这种方式对界面元素的操作是随机或者简单规则订制的,无法保证界面元素的覆盖比例,更难以评估测试效果。

基于Monkey的思路,逐渐形成了一种自动化测试方法称为“UI遍历”,其主导思想是尽可能多地去操作被测app的界面元素,每个元素至少操作一遍,同时配以后台监控,实时关注系统日志,实时获取被测对象的状态,也可以利用hook等渗透性手段记录和分析内部行为,获取到更深层的数据,定位问题所在。

 360QA中心推出的开测平台已经相对完善地支持了UI遍历的测试,可以高效地完成大量Android app的稳定性、兼容性、安全性、性能等测试。本文将介绍360QA中心使用的一种探索式UI遍历方法:Smart Monkey。

Smart Money,作为一种探索性UI遍历方法,其代码实现在Android和IOS上有所不同,但其计算模型是通用的。本文希望籍此能向所有从事UI遍历方法研究的人员提供帮助。



Smart Monkey对UI遍历测试的解决方法





UI遍历的首要目标是尽可能多地访问到操作过程中出现的界面元素,二是在这个基础之上尽可能多的覆盖被测对象的逻辑分枝。先解决如下问题:

1.界面元素及其结构


各界面元素可以最直观的归纳为一个树型的结构,每个元素有且只有一个父元素,零个或多个子元素。界面树有一个抽象的根结点,根结点的直接子元素为app的各个窗口,各窗口的子元素可以为视图、列表等,列表的子元素为各列表项。

不论是在Android UIAutomator还是IOS UIAutomation框架中,每个界面元素都是一个特定类的对象,为了描述方便,本文以IOS UIAutomation框架为例,但其原理在不同的平台上是相通的。如按钮是UIAButton类对象、文本框是UIATextField类对象,所有元素的基类都是UIAElement。类中封装了元素的操作方法,如用tap方法进行点击、用scrollToVisible方法拖拽到屏幕可视区等。


2.界面元素的标识


需要对各元素进行标识,即为每个元素设定一个ID,保证不同的元素有不同的ID。但元素ID的设定并无固定的方法,可以通过元素名称、类名、在元素树中的序号等来作唯一标识,也可以考虑元素的面积、坐标位置等特征。本文采用的方法是:

元素ID = 名称 + 类名 + 父元素ID

其中名称由元素的name方法获取。通过这个方法设定的ID有可能很长,可以考虑一定的压缩,但不应破坏其唯一性。

3.历史记录与访问计数

需要一个结构来记录元素的访问情况,这个结构称为历史记录,每个元素对应一条记录,先设定三个概念:前导元素、产生元素、产生层级。设元素E1是由访问元素E0后产生的,那么E0就是E1的前导元素,E1就是E0的产生元素,如果E0是起始界面中就存在的,那么E0的前导元素为空。一个产生元素逐层向上寻找其前导元素,直到空时所经历的层数,称为其产生层级。

例如:起始界面上有按钮A,点击之后又产生了两个按钮B、C,点击B后又出现一个按钮D,那么B、C的前导元素即为A,A的产生元素是B、C,D的前导元素是B,其产生层级为3。每个元素的历史记录中有四个重要参数:

①visitTimes

已经访问的次数,每次访问时增1,起始为0

②gCnt

该元素的产生元素的个数

③preOperated

该元素的前导元素

④rCnt

产生元素已被访问的个数

这四个参数组成了元素的访问计数,当visitTimes为0,说明该元素尚未被访问过,当gCnt 大于 rCnt时,说明该元素尚未访问完全。每次操作一个元素时,如果这个元素是第一次被操作,那么它的前导元素的rCnt应该增1,当前导元素的gCnt等于rCnt时,说明前导元素已访问完全,不需要再操作了。

访问记数的引入是为了更多的访问出现过的元素。例如,菜单中的元素在操作之后可能菜单就消失了,但菜单按钮的gCnt参数是其菜单项的个数,rCnt是已经访问过的菜单项的个数,当其gCnt大于rCnt时,说明菜单按钮的访问不完全,还需要继续点击,继续展示出菜单项。

4.界面元素的排序及选择

理想情况下,在选择当前应该操作的元素时,应该分析出当前界面可以完成的功能,并将各元素按其语意进行排序,选出当前最应该操作的元素,但这种方法还在研究中,本文先谈已实现的方法

为每个元素设定一个权重,然后将各元素按权重排序,选出权重最大的元素,即为当前操作的对象。权重的设定按下列规则进行:

①权重的初始值 = 元素的产生层级*C + 元素在界面树中的层级(C为常数),经过比较,笔者发现先访问层级深的元素比先访问层级浅的元素在多数情况下可以更好的覆盖逻辑分枝,例如先访问列表内部的元素比先访问导航栏里的元素更有利于覆盖更多的功能。常数C在实现中被设为5,意味着产生层级为权重的主要指标,树层级为次要指标。

②具有否定意味的元素要小于肯定意味的元素。例如,名称为“取消”的元素应小于名称为“完成”的元素。

③未访问过的且可视的元素大于未访问过但不可视的元素。

④未访问过的但不可视的元素大于访问不完全的元素。

⑤访问不完全的元素大于具有“返回”等界面跳转意味的元素。

⑥具有“返回”等界面跳转意味的元素大于已访问完全的元素。

⑦当有多个具有“返回”等界面跳转意味的元素时,它们的权重是一个随机值,即每个按钮都可以有机会被选到。

按这种方法,一个排序即可选出当前应该操作的元素。

5.状态突破

如果当前界面的元素都已经访问完全,但又没有可以使界面跳转的元素,或者连续点击界面跳转的元素多次,又始终找不到可访问的元素时,这时就需要进行状态突破。

状态突破是一组操作的尝试,包括屏幕左滑、点击屏幕中心、右滑、下滑、再右滑,点击屏幕随机位置,从当前元素中随机选择并操作等等。

例如,当app刚启动时展示“欢迎页”,这时遍历程序发现没有可操作的元素时,就应该进入状态突破流程了,尝试了左滑无效,点击屏幕中心无效,到了右滑n次后,app进入主界面,有可操作的元素了,于是遍历程序进入前面的流程中继续工作。

6.忽略机制

遍历程序应该兼顾广度和深度,当一个界面元素有非常多的子元素时,可以考虑忽略掉一部分相同结构的元素,如一个列表元素有太多列表项时,就应该忽略掉一部分。

还有一种情况并非少见,即一个界面只要一展示,就会有未访问过的元素成生,如果不加控制遍历程序会被困死在这个界面内,解决方法是在历史记录中记录每个界面的最大元素个数和页面的展示次数,当一个界面的展示次数超过其最大元素个数一定量的时候,就忽略掉新元素。

这种方法需要为每个界面也做一个唯一标识,目前的方法是将主窗口第一级的元素类名按顺序组成的字符串作为界面的ID。在Android平台上,还可以考虑加入Activity的名称。

7. 其他关键点

(1)  特殊元素的ID设定

用前面的方法设定文本框和键盘的ID后,文本框ID应再加上序号,即树中第几个文框。键盘ID再加上当前有输入焦点的元素的ID。

(2)登录的相关操作

需要对登录界面进行识别,从而输入用户名和密码,登录界面的特征比较明显,当界面中出现文本框、密码框和登录按钮时,即可判断为登录界面。

(3)忽略不可再现的元素

当访问一个非访问完全的元素时,应记录上一次访问该元素时其gCnt和rCnt的差值,如果此次访问时的差值与上一次相同,应该忽略掉这个元素。

这种情况的出现往往是由于元素的产生元素中有不可再现的元素,所以应该忽略。

(4)不可视元素的操作

可以看出本文对元素的遍历顺序是先访问可视的元素,对于不可视的元素需要调用某种方法将其拖拽到可视区域之后再进行操作,如在IOS上用scrollToVisible,Android上用scrollIntoView等方法,如果拖拽失败则放弃对该元素的访问。

(5)不可用元素的操作

有些元素在访问时不可用,可以直接忽略,也可以在历史记录中加一个参数disabledTimes,如果元素在访问时不可用即将disabledTimes增1,如果该元素当前可用,而disabledTime等于visitTimes,则将此元素视为未访问过的元素,访问之后将disabledTimes设为-1即可。

(6)文本框的操作

文本框的操作点击即可,实际的输入由键盘的操作完成,也可以简单地用某种方法直接设定文本实现对文本框的输入,在手机app中文本框往往有一个初始值,如“请输入订单号”等,遍历程序可以根据这种初始值来设定输入的具体内容。

(7)界面跳转元素的判定

可以通过元素名称来判断,如有“返回”、“关闭”、“go back”等字样的元素。如果不能通过元素的名称判断出哪些元素可以引起界面跳转,可以考虑屏幕最左上角的按钮和左下角的按钮,往往可以起到返回主界面的做用。

(8)遍历结束的判断

但当状态突破超过一定次数,而仍无可访问的元素时,遍历程序也就该结束了。


8. Smart Money流程图Smart Monkey

0 1