基于行为树模型的Android应用GUI自动随机测试方法
2021-05-14佘学文陈向宇刘东启
佘学文 陈向宇 刘东启
1(广东岭南职业技术学院 广东 广州 510663) 2(华南理工大学计算机科学与工程学院 广东 广州 510006)
0 引 言
随着人工智能和移动互联网的迅猛发展,智能手机已经成为人们生活的重要部分。美国媒体机构Zenith发布的最新研究报告显示, 2018年中国智能手机用户数达到13亿,位居全球第一,全球智能手机用户数也达到33亿,并且还在逐年增加。图形用户界面(Graphical User Interface,GUI)是用户与手机应用程序(App)进行交互的最重要通道。在激烈的市场竞争中,高质量、无瑕疵的GUI是一款应用程序成功的重要前提,GUI测试是保证应用程序GUI质量的重要手段。目前,学术界和工业界已经研究、实现和评估了多种GUI测试的方法[1-6],但Joorabchi等[7]一项关于移动App开发面临的挑战的研究表明,超过70%的移动应用开发或测试人员在实践中倾向于采用手动方法进行GUI测试,从事全自动GUI测试的人数不到5%,超过一半的参与者认为实现自动化GUI测试是一项具有挑战性的工作,且移动应用GUI测试目前仍然是一项劳动密集型工作。
为了提高Android应用GUI测试的效率和自动化水平,本文建立一套易于实现、开展测试的前置条件简单且更加高效的Android应用GUI自动化随机测试方法,该方法在开展测试前只需要简单的准备工作,同时采用以下手段来保证更好的代码覆盖率:
1) 在测试时通过映射GUI树和行为树模型来避免静态分析。
2) 动态更新模型以增加用户在使用应用程序过程中很少或从未使用过的事件的概率。
3) 应用统计模型建立行为树模型。
1 相关工作
目前,工业界和学术界已经在Android应用GUI自动化测试方面开展了许多工作。Google提供的Android SDK中,给出了三种可用于自动化测试的方式,即Monkey、MonkeyRunner和Instrumentation。其中Monkey[3]是测试Android应用程序最常用的工具,它通过向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等)对被测应用程序(Application Under Test ,AUT)进行有效的自动化测试。但Monkey自动生成的大量输入很简单,无法生成需要人类智能组合的测试输入,且会生成很多冗余输入。文献[4-5]采用了基于Hook机制的GUI自动化测试方法。文献[8]采用的基于随机探索的方法。文献[9]采用了基于模型(MBT)的方法并研制了工具AndroidRipper。该工具维护一个GUI状态机模型,在执行测试过程中,AndroidRipper通过深度优先搜索(DFS)策略动态分析GUI的控件获取其可触发的事件序列,每一个事件序列就是一个测试用例。文献[10-11]提出基于捕获用户输入的GUI自动化测方法,其中文献[11]创建了一个名为MonkeyLab的工具,该工具通过挖掘GUI的模型为自然和非自然事件序列生成可操作的场景。
2 方法设计
本文提出的基于行为树模型的GUI自动化随机测试方法的创新之处在于开展测试的前置准备过程简单,且测试过程中会动态更新行为树模型以增加测试覆盖率。初始行为树模型是通过统计建模从使用日志中创建的,考虑到Android应用的部分事件可能在使用日志中没有出现过,提出通过将行为树模型中的事件映射到GUI树中的控件来解决,同时行为树模型中事件的概率也随着测试的进行而动态调整。图1为本文方法的总体框架,主要分为六个步骤。
图1 方法总体框架
1) 从使用记录器中预先收集使用日志,并利用Hierarchy Viewer从AUT中提取GUI树。
2) 应用统计模型创建行为树模型,然后将行为树模型中的事件映射到GUI树中的控件,以便根据要执行事件序列,自动进行GUI控件操作,实现GUI的自动化测试。
3) 从行为树模型中随机选择事件,生成执行事件序列。
4) 将所选事件触发到AUT。
5) 对使用日志进行日志分析,根据分析结果得到用户执行某事件的频率,并根据事件频率调整概率,动态更新行为树模型。
6) 重复步骤2)至步骤5)直到达到时间限制或预先确定的事件数量。
2.1 日志获取与GUI树创建
此步骤的目的是获取用于生成行为树模型的控件、使用日志和GUI树。
2.1.1使用日志获取
获取使用日志是本文方法开展测试的唯一前置条件和步骤。使用日志是通过使用记录服务Recorder从AUT获得的。Recorder服务使用Android的AcciblityService实现,该服务以AccessibilityEvent的形式捕获测试人员或用户执行的事件,然后收集这些事件并通过Android调试桥(Android Debug Bridge,ADB)传输到Observer。如表1所示的事件,如果Recorder服务开启,那么一旦用户开始使用应用程序,Recorder服务就会记录用户的使用日志,直到用户关闭该应用程序。由于这些使用日志是建立行为树模型的基础,因此覆盖的使用场景越多越好,测试方可以通过众包的方式获得大量使用日志数据。
表1 AccessibilityEvent定义的几种事件类型
续表1
2.1.2从AUT中提取GUI树
GUI树是GUI控件的层次结构,在运行时使用Android SDK工具包中的可视化调试工具Hierarchy Viewer从AUT中提取。Hierarchy Viewer 通过ADB与 Android 模拟器或 Android 真机进行通信,可以列出应用程序的树形结构布局,并提供所有 GUI 控件的ID、控件类型、文本内容、位置和大小等信息。本文使用图2所示的图片编辑程序来作为测试样例进行说明,图3显示了图2中示例活动的简化GUI树。在这个例子中,简化的GUI树包括6个GUI 控件:e1.backButton、e2.editButton、e3.deleteButton、e4.shareButton、e5.imageView和e6.saveButton 。
图2 样例AUT(图片编辑程序)
图3 AUT的GUI树
2.2 行为树模型生成和映射
在这个步骤中,根据使用日志创建行用户执行事件的行为树模型,然后将事件映射到GUI树中的GUI 控件。
2.2.1行为树模型生成
通过使用马尔可夫假设近似条件概率从使用日志创建行为树模型(如图4中的简化行为树模型)。
图4 简化的行为树模型
本文使用N-gram语言模型来实现,N-gram 是一种基于统计语言模型的算法,又被称为一阶马尔可夫链,它的基本思想是将文本里面的内容按照单词进行大小为N的滑动窗口操作,形成长度是N的单词片段序列。在软件测试的背景下,这些单词代表事件,n表示事件的数量。例如,一系列事件etap1,etap2,ehold1,eswipeUp,如果设n=2,那么2-gram为:
1)p(etap2|etap1)
2)p(ehold.1|etap2)
3)p(eswipeUp|ehold.1)
如果设n=3,那么3-gram为:
1)p(ehold.1|[etap1,etap2])
2)p(eswipeUp|[etap2,ehold.1])
其中,p(ex|[ej,ek])是在给定历史事件[ej,ek]下选择事件ex的概率,当n较大时,模型可以存储更多上下文,从而可以更加充分地进行时空权衡。在实际中,用户的使用范围可能无法完全覆盖应用程序的所有功能。在图4中,假设当用户处于活动B时,可能发生另一个事件e6,但简化的行为树模型中没有该事件,这意味着模型未对程序的事件实现完全覆盖,且事件e6永远不会被映射、选择和执行。因此,将GUI树中可用、但在模型中不存在的事件称为未知事件。
为了解决这个问题,需要调整概率分布。常用的N-gram训练工具有SRILM、IRSTLM、BerkeleyLM和KenLM等[12-14],这几种工具所用的算法思想基本一致,本文以KenLM(速度最快,占用内存最少)作为训练工具,所用的平滑技术是Modified Kneser-ney smoothing[15]。因为它被认为是当前一个标准的、广泛采用的、效果最好的平滑算法,Modified Kneser-ney smoothing平滑技术有三个核心思想。
1) 绝对折扣。为了给未知事件一些概率,必须降低其他事件的概率,以保持有效的概率分布。
2) 插值。递归地组合所有k-gram的概率,其中k∈1,2,…,n,如果一个事件序列在模型中出现任何k-gram下标,那么它将产生非零概率。
3) 历史。应该考虑每个事件出现的上下文的数量。例如,如果一个事件只发生在特定的上下文中,那么它就不太可能出现在新的上下文中。
2.2.2将行为树模型映射到GUI树
行为树模型中的每个事件都使用唯一的resource-id作为键映射到GUI树中的GUI控件,如果没有定义resource-id,则使用类型和文本映射到GUI控件。为了提高查找速度,本文使用哈希表实现GUI映射器,并在每次重新获取使用日志信息后进行更新。
2.3 选择事件
本文的目的是测试应用程序,而不是创建一个自然的动作序列,因此,动作序列中的下一个事件并不会简单地依据概率的高低选择,而是随机选择。设e1,e2,…,en∈{possibleEvents},且h是先前选择的历史事件,事件选择器将根据给定的一系列先前所选事件的平滑概率来随机选择enext:
enext=w([p(e1|h)],[p(e2|h)],…,
[p(en|h)])
(1)
图5 平滑后的行为树模型
2.4 执 行
Event Executor执行由事件选择器在实际移动设备或仿真器上通过UI Automator选择的enext,本文方法可以执行诸如单击、长按、滚动和文本编辑等事件,这些事件定义如下:
单击:点击并立即在视图中释放。
长击:在视图点击并按住3 s后释放。
滚动:点击并拖动到x+Δx,y+Δy位置。
文本编辑:输入任意的预生成的字符串。
假设enext为图4中的e6,并且是可点击的,Event Executor将向视图的中心触发一个单击事件,在这种情况下,本例中为saveButton。
2.5 更 新
执行后,利用偏置随机技术对模型进行更新,以调整所选择/执行的事件的概率,它减少了先前选择和执行的事件的小因子。
p′(ex|h)=p(ex|h)-d(ex,δfx)
(2)
式中:fx是ex的频率,d(ex,δfx)是ex的折扣值,p(ex|h)是给定历史事件h下事件ex发生的概率。假设d(e6,δf6)=0.005,那么根据式(2)可以得到p′(e6|h)=0.025,在从ex中减少一些概率之后,必须重新计算每个p′的概率,以便通过将其除以总p′概率来保持有效的概率分布。
(3)
式(3)的结果如图6所示。p(e6|h)的概率降低了,但p(e1|h)至p(e5|h)略有增加,这将使其他事件有更大的机会被选择,从而提高代码覆盖率。最后,在执行e6后更新器更新行为树模型。
图6 更新后的行为树模型
3 实验与分析
为了评估本文方法的有效性,将其与另外三种主流的方法进行比较:Android Monkey、手动测试和Dynodroid工具。评估采用的目标程序是三个未经修改的开源Android应用程序:Anymemo[16]、World Clock[17]和Weight Chart[18]。这三款工具分别具有动态内容、静态内容和复杂的用户界面,可以在一定程度上保证评估的覆盖面和可信性。
表2 性能评估程序
3.1 实验设置
所有的实验都使用Android API 19在Nexus 5模拟器上完成的,该模拟器具有1 586 MB的RAM,运行在64位Windows 7计算机上,具有3.1 GHz的i7处理器和16 GB的RAM。让5个学生分别使用5分钟上述应用程序来获取使用日志,对他们如何使用这些应用程序没有任何限制,且每次实验AUT都安装在新创建的模拟器上,同时只使用默认设置。每一次实验,根据本文方法开发的工具、Android Monkey和Dynodroid都包含5 000个触摸事件,为了确保每次执行下一个事件之前完成屏幕切换或动画,在每个事件之间设置500 ms的延时。对于手动测试,要求测试人员在40 min内尽可能多地手动执行这些应用程序。在每次实验后都会重置模拟器以防止它影响后续的测试,同时使用EMMA覆盖率检测工具[19]和自定义shell脚本从AUT收集覆盖率信息。
3.2 结果分析
在每个程序设置了10个数据采集点,每500次事件间隔读取一次代码覆盖率,测试结果如表3所示。Our_COV代表本文方法的覆盖数据,Monkey_COV代表Android Monkey的覆盖数据,Dynodroidy_COV代表Dynodroidy的覆盖数据,Manual_COV代表人工手动测试的覆盖数据,表中的数字表示每种方法所覆盖的代码行数和代码覆盖率。测试结果表明,在Anymemo中,本文方法的性能优于Android Monkey和Dynodroid,但是没有手动测试好。在3个应用程序测试中,人工手动测试的代码覆盖率均是最高的,这是可以预见的,因为人类可以提供更智能的文本或顺序输入。
表3 四种测试方法代码覆盖率对比
图7显示了Anymemo的累积代码覆盖率。X轴表示基于500个事件间隔的事件数量。为了不在测试期间干扰受试者,在手动测试期间没有记录覆盖率,所以手动测试的数据为最终覆盖率。
图7 Anymemo的累积代码覆盖率
4 结 语
本文介绍了一种基于行为树模型的Android应用GUI自动化随机测试方法。该方法基于实际使用日志创建行为树模型,在运行时用GUI树映射行为树模型,用改进的Kneser-Ney平滑技术处理零概率未知事件。为了评价本文方法的有效性,设置了实验,通过3个开源应用程序与Android Monkey、手动测试、Dynodroid等方法进行了对比。测试结果表明,本文方法在所有应用程序上都优于Android monkey,在Anymemo、World Clock上优于Dynodroid,但是落后于手动测试。未来,将扩展本文方法能够处理的可操作事件,如缩放、拖拽等。同时通过更复杂的Android应用程序来评估本文提出的工具。