Fastbot 开源版技术原理与架构

技术

文章来源|字节跳动软件工程实验室 Repo | github.com/bytedance/Fastbot_Android

0 1

问题背景

近年来,移动应用程序的数量呈现爆炸性增长,随之而来的是用户对应用程序质量的高要求。确保应用程序的质量对于维护用户忠诚度和业务成功至关重要。为了满足这一需求,自动化 GUI 测试已经成为一种吸引人且成本效益高的解决方案。在实际应用中,工业级应用程序经常需要进行更新以适应不断变化的用户需求。例如,工业厂商一般每周都会发布一个新的核心应用版本,因此持续测试对于及时了解应用程序质量的反馈至关重要,一般通过进行冒烟测试来评估每个新的内部版本。

然而,简单地采用现有的测试工具虽然可行,但测试效率低且效果不佳。传统的 GUI 测试工具只是简单地重新运行每个版本的应用,并没有充分利用之前测试运行中的知识来加速当前正在进行的 GUI 测试。

为了解决这个问题,字节跳动软件工程实验室(https://se-research.bytedance.com/)团队提出了一种 基于强化学习的可复用的基于模型的自动化安卓测试工具 Fastbot 。该工具旨在利用强化学习的技术,通过学习和推理从之前的测试运行中获得的知识,从而达到更快更高效的测试效果。

下面将逐一介绍工具的 工作流程、核心概念、算法原理 以及 设计实现

02

工作流程

picture.image

Fastbot 是一种利用强化学习的可复用的基于模型的自动化安卓测试工具。它接受一个给定的应用程序版本,以 APK 文件的形式作为输入,并输出覆盖报告和找到的崩溃。Fastbot 的工作流程包括两个主要阶段,如图所示:

(a) 测试前的设置。a1 对 APK 文件进行反编译,收集控件的静态文本信息。a2 在一组设备上安装 APK,同时 a3 加载先前测试运行中的历史测试数据填充模型。

(b) 引导式 UI 探索。b1 从被测应用程序中获取当前的 GUI 页面,b2 识别和抽象出当前页面上的可用 hyper-event(超事件,一组具有相同属性的事件,将在下文具体解释)。b3 选择一个具体的 UI 事件,该事件有可能增加 Activity 覆盖率,b4 执行该事件。执行完毕后,b5 更新历史测试数据、概率模型,同时 b6 更新强化学习智能体。

这些步骤将循环迭代,直到使用完时间预算。

03

核心概念

picture.image

04

技术和算法原理

Fastbot 的关键思想是利用存储在概率模型中的先验知识,去有效地指导 GUI 测试。为了实现这一点,关键步骤是决定在当前 GUI 页面上选择哪个 UI 事件,可以快速地提高 Activity 覆盖率。具体而言,给定一个 GUI 页面,Fastbot 提取当前所有可用的超事件,并采用以下两种策略协同组合去选择执行的事件:(1)基于模型的事件选择,(2)基于学习的事件选择。

4.1 基于概率模型的事件选择

picture.image

模型扩展:如果当前 GUI 页面中的某些超事件尚未包含在概率模型𝑀中,Fastbot 将启动扩展策略,随机选择一个尚未执行的超事件。在实际中有两种可能的情况:1)先前的测试运行可能没有覆盖所有的超事件,2)当前测试应用程序版本中添加了一些新的功能。该模式可以帮助扩展模型并优先探索潜在的新功能。

picture.image

4.2 基于强化学习的事件选择

前面概率模型只能表达一步的指导信息,而强化学习技术能够将一步扩展为多步的指导信息。Fastbot 采用了 Sarsa N-Step 算法作为奖励函数去计算和更新 Q 值。

picture.image

picture.image

4.3 案例解释

为了加深理解,下面用头条应用来对算法的几种决策进行解释:

  1. 概率模型的探索与利用模式

通过对历史数据记载对概率模型 M 初始化,见图 b,启动头条应用后,进入 home Activity1,当前页面可以抽象为 3 个 hyper-event,这三个事件都被包含在模型中,因此 Fastbot 回启动模型利用策略选择事件,看图 b 左边部分,可以知道 e3 有 90%的概率留在 Activity1,因此更倾向于选择 e1 和 e2,假设选择 e1 后,到达 Activity2,在 Activity2 中 e4 已经在模型中,并且 100%回到 Activity1,同时 e5,e6 不再模型中,此时 Fastbot 将启动探索模式,随机选择 e5 或者 e6,如果选择 e5,到达 Activity3,此时模型添加一条 e5-Activity3 的概率值 100%,同时由于 e1 的执行次数加 1,因此 e1 的概率也要改变,e1-Activity2 的概率变为 0.7/1.1=63.6%,e1-Activity5 的概率变为 36.4%,更新为图 b 右半部分。

picture.image picture.image

b. Q 表的更新利用

在图 a 中,Activity2,e4,e6 没有被执行过,同时 e6 不在模型内,因此 e1 的奖励更高,相似的,e7,e8 也是新的事件,因此 e5 的奖励会更高,假设 e1,e2,e3 都会执行过很多次,并且 Activity2,3,4 都被覆盖了,此时将利用 Q 表中的值去计算事件选择的概率,在当前 Activity1 中,由于 e1 的奖励最高说明他能够到达更深的 Activity,因此选择 e1 作为下一个事件执行。

picture.image

05

设计实现

Fastbot 开源版包括客户端和本地服务端两部分,客户端负责监听 UI 事件,接收和注入相应的动作,服务端负责计算和决策。具体而言,在每个设备上运行 Fastbot 客户端,通过监控 GUI 页面信息发送给服务端,服务端接收信息根据算法决策返回选择的事件,客户端接收事件并执行操作。

客户端使用 Java 语言编写,用于获取 GUI 信息,读取服务端决策,并将决策转化为设备可以执行的代码,从而操作设备;本地服务端,即与 Java 层相对应的底层 C/C++代码层,以动态链接库(.so 文件)的形式与 Java 层通过 JNI 接口进行交互,它用于实现用户偏好的读取,模型的学习和任务决策,并将决策结果转化为 JSON 格式的信息传递给 Java 层。

Fastbot 的实现继承 Monkey 原生框架,下图展示了 Fastbot 扩展的代码简要结构图,在 java 层新增了来自 Fastbot 算法返回的事件源 MonkeySourceApeNative 类,对 GUI 树的获取,以及对 Android 不同的系统的兼容的 Adapter 适配接口,此外,为了支持自定义操作的解析和执行对 Monkey 的原始事件进行了封装。

picture.image

06

常用配置

6.1 配置自定义事件

Fastbot 支持自定义事件序列,适用于场景覆盖不全,通过人工配置到达 Fastbot 遍历不到的场景。

配置步骤:

1.新建 max.xpath.actions 文件(文件名称固定不能更改)

2.参照案例格式指定控件和相应的动作。其中:

a.prob:发生概率,"prob":1,代表发生概率为 100%

b.activity:所属场景

c.times:重复次数,默认为 1 即可

d.actions:具体需要执行的事件序列,其中要指名每个操作对象的 xpath,对应的动作 action,和与下一个事件间隔的时间 throttle(ms),注意 xpath 写法

3.动作类型(必须大写):

a.CLICK:点击,想要输入内容在 action 下补充 text,如果有 text 则执行文本输入

b.LONG_CLICK:长按

c.BACK:返回

d.SCROLL_TOP_DOWN:从上向下滚动

e.SCROLL_BOTTOM_UP:从下向上滑动

f.SCROLL_LEFT_RIGHT:从左向右滑动

g.SCROLL_RIGHT_LEFT:从右向左滑动

4.配置完成后,将配置文件推送到手机端: adb push 路径+max.xpath.actions /sdcard

下面以 AmazeFileManager 为例:

1. 第一种情况:当事件执行不涉及 Activity 的跳转时,只需将所有的事件序列写在一个对象中。

如图所示,actions 字段里的 4 个动作分别对应下图中红框标出的动作,(1)点击菜单按钮打开菜单栏,(2)点击 recent file 按钮到达相应文件目录,(3)点击加号按钮,打开浮选选项,(4)点击 File 按钮打开新建文件对话框。

picture.image


          
[
          
    {
          
        "prob":1,
          
        "activity":"com.amaze.filemanager.ui.activities.MainActivity",
          
        "times":1,
          
        "actions":[
          
            {
          
                "xpath":"//*[@content-desc='Navigate up']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            },
          
            {
          
                "xpath":"//*[@resource-id='com.amaze.filemanager:id/design_menu_item_text' and @text='Recent files']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            },
          
            {
          
                "xpath":"//*[@resource-id='com.amaze.filemanager:id/sd_main_fab']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            },
          
            {
          
                "xpath":"//*[@resource-id='com.amaze.filemanager:id/menu_new_file']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            }
          
        ]
          
    }
          
]
      
  1. 第二种情况:当事件执行涉及到 Activity 的跳转时,要将对应不同 Activity 的事件序列单独存放。

下图展示了从 MainActivity 跳转到 PreferencesActivity 的例子。

picture.image

可以看到在配置文件中有两个对象,分别对应 MainActivity 和 PreferencesActivity 两个页面下需要执行的事件序列。


          
[
          
    {
          
        "prob":1,
          
        "activity":"com.amaze.filemanager.ui.activities.MainActivity",
          
        "times":1,
          
        "actions":[
          
            {
          
                "xpath":"//*[@content-desc='Navigate up']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            },
          
            {
          
                "xpath":"//*[@resource-id='com.amaze.filemanager:id/design_navigation_view']",
          
                "action":"SCROLL_BOTTOM_UP",
          
                "throttle": 2000
          
            },
          
            {
          
                "xpath":"//*[@text='Settings' and @resource-id=['com.amaze.filemanager:id/design_menu_item_text']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            }
          

          
        ]
          
    },
          
    {
          
         "prob":1,
          
         "activity":"com.amaze.filemanager.ui.activities.PreferencesActivity",
          
         "times":1,
          
         "actions":[
          
                 {
          
                     "xpath":"//*[@resource-id='android:id/title' and @text='Appearance']",
          
                     "action":"CLICK",
          
                     "throttle": 2000
          
                 }
          
             ]
          

          
    }
          
]
      
  1. 带文本输入的情况

配置格式: 在 action 字段选择“CLICK”,同时添加“text”字段存储需要输入的文本。

picture.image

以抖音为例,使用以下配置信息可以指定完成输入账户信息的操作。两个动作,分别对应点击 use phone 按钮和输入文本。


          
[
          
    {
          
        "prob":1,
          
        "activity":"com.ss.android.ugc.aweme.account.login.auth.I18nSignUpActivityWithNoAnimation",
          
        "times":1,
          
        "actions":[
          
            {
          
                "xpath":"//*[@resource-id='com.zhiliaoapp.musically:id/ayo' and @text='Use phone / email / username']",
          
                "action":"CLICK",
          
                "throttle": 2000
          
            }
          

          
        ]
          
    },
          
{
          
        "prob":1,
          
        "activity":"com.ss.android.ugc.aweme.account.login.v2.ui.SignUpOrLoginActivity",
          
        "times":1,
          
        "actions":[
          
            {
          
                "xpath":"//*[@text='Phone number' and @resource-id=['com.zhiliaoapp.musically:id/e61']",
          
                "action":"CLICK",
          
                "text":"12341828506",
          
                "throttle": 2000
          
            }
          

          
        ]
          
    }
          

          
]
      

6.2 屏蔽控件

Fastbot 支持手动配置需要屏蔽的控件或区域,比如测试过程中“半路”中途退出登录,屏蔽退出登录按钮。

配置步骤:

  1. 新建 max.widget.black 文件(文件名称固定不可更改)
  2. 参照案例格式指定需要屏蔽的控件,格式如下:
  • bounds:屏蔽某个区域,在该区域内的控件或坐标不会被点击。
  • xpath:查找匹配的控件,屏蔽点击该控件。
  • xpath+bounds:查找匹配的控件,当控件存在时屏蔽指定的区域。
  1. activity:当 activity 与 currentactivity 一致时执行如下匹配
  2. 屏蔽控件或区域共有三种方式:
  • 配置完成后,将配置文件推送到手机端:adb push 路径+max.widget.black /sdcard

下面以 AmazeFileManager 为例,展示如何进行控件,区域以及树剪枝屏蔽:

picture.image

  1. 屏蔽控件

如图(a)所示,红框标出来的黑色区域控件是手动配置的屏蔽控件。在这里,适用 xpath 来指定需要被屏蔽的控件。


          
[
          
{
          
    "activity":"com.ss.android.ugc.aweme.main.MainActivity",
          
    "xpath":"//*[@content-desc='Navigate up']"
          
},
          
{
          
    "activity":"com.ss.android.ugc.aweme.main.MainActivity",
          
    "xpath":"//*[@content-desc='More options']"
          
}
          
]
      

2.屏蔽区域

如图(b)所示,红框标出来的黑色区域控件是手动配置的屏蔽区域。在这里使用 bounds 来配置屏蔽区域。


          
[          {              "activity":"com.ss.android.ugc.aweme.main.MainActivity",              "bounds":"[0,18],[240,60]"          }          ]
          

      

3.树剪枝屏蔽

树剪枝屏蔽是指在 GUI 树中查找到对应控件,通过将控件属性的 enable 设置为 False,从而使控件屏蔽。

配置步骤:

  1. 配置 max.tree.pruning 文件(文件名固定不可更改)
  2. 参照案例格式指定需要屏蔽的控件,格式如下:
  • activity:当 activity 与 currentactivity 一致时执行如下匹配
  • 剪枝方式:配置 xpath,查找匹配的控件,改变控件属性,从而使控件屏蔽。
  • 配置完成后,将配置文件推送到手机端: adb push 路径+max.tree.pruning /sdcard

例子:仍以 AmazeFileManager 为例 ,如上图(c)所示,被红框标出的黑色区域即为手动配置的树剪枝屏蔽控件,可以通过将控件的 enabled 属性变为 flase,也可以将其他属性变为空来实现屏蔽。


          
[
          
{
          
    "activity":"com.ss.android.ugc.aweme.main.MainActivity",
          
    "xpath":"//*[@content-desc='Navigate up']",
          
    "enabled":"false"
          
},
          
{
          
    "activity":"com.ss.android.ugc.aweme.main.MainActivity",
          
    "xpath":"//*[@content-desc='More options']",
          
    "enabled":"false"
          
},
          
{
          
    "activity":"com.ss.android.ugc.aweme.main.MainActivity",
          
    "xpath":"//*[@resource-id='com.amaze.filemanager:id/search'",
          
    "resourceid":"",
          
    "contentdesc":"",
          
    "text":"",
          
    "classname":""
          
}
          
]
      

0 7

更多信息

Fastbot 开源 地址:

https://github.com/bytedance/Fastbot\_Android

更多 Fastbot 技术细节请参考该论文:“Fastbot2: Reusable Automated Model-based GUI Testing for Android Enhanced by Reinforcement Learning”。Zhengwei Lv(吕正伟), Chao Peng(彭超), Zhao Zhang(张钊), Ting Su(苏亭), Kai Liu(刘凯), Ping Yang(杨萍)。37th IEEE/ACM International Conference on Automated Software Engineering (ASE 2022).

注:此次 Fastbot 的开源工作由字节跳动软件工程实验室(https://se-research.bytedance.com/)推动,华东师范大学苏亭教授的研究小组(https://mobile-app-analysis.github.io/)深度参与并提供了技术支持,多位来自华东师范大学的研究生参与了 Fastbot 的开源工作或帮助改进,包括许梦倩(硕士研究生、研究实习生)、刘凯(硕士研究生、研究实习生)等。

picture.image

点个“ 在看 ”不失联

0
0
0
0
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论