之前写到过 AI 的代码可以通过形式化验证来保证安全性和正确性,但是对于移动端还是得通过实际测试,所以好奇 AI 给移动端测试带来的发展,本文来了解一下移动端的自动化测试。

从 Monkey 随机乱点到 LLM 驱动的智能体自主探索——移动端 GUI 测试正经历一场范式转移。这篇文章先从传统方法的三大瓶颈讲起,再拆解 GPTDroid、DroidBot-GPT、DroidAgent 三个开创性工作,看看大语言模型是如何第一次"拿起手机"测 App 的。

注:本文有 AI 辅助创作,确实排版和阅读都比纯手工更好。


1、先说结论

移动端 UI 自动化测试正在从"定位控件并点击"转向"理解语义并推理"。这不是一次增量改进,而是一次范式转移。

本文的核心观点:

  1. 传统 UI 测试的三大瓶颈(脆弱定位、跨端鸿沟、Oracle 缺失)都源于同一个根因:机器不理解页面上写的是什么。
  2. LLM 天然具备三种传统测试工具缺失的能力:理解自然语言语义、生成有意义的文本输入、进行多步推理。
  3. 2023-2024 年的三个开创性工作(GPTDroid、DroidBot-GPT、DroidAgent)已经验证了这条路径的可行性,并将 Activity 覆盖率提升了 32%。

全文约 7500 字,适合有一定客户端或测试工程背景的读者。


2、传统 UI 测试为什么"越做越痛"?

如果你做过客户端开发或 QA,大概率经历过以下场景:

2.1、痛点一:一次 UI 改版,百条脚本阵亡

你基于 Espresso 或 XCUITest 写了 200 条回归测试。设计师改了首页布局——搜索栏从顶部移到了浮层弹窗里——于是所有涉及"搜索"的测试用例集体红屏。

问题的根源在于:传统测试脚本通过控件 ID(Resource ID) 或 XPath 定位页面元素。这类定位器高度依赖 UI 的层级结构,稍有变化就会断裂。

1
2
3
4
// 典型的 Espresso 测试:通过 Resource ID 定位
onView(withId(R.id.home_search_bar)).perform(click())
onView(withId(R.id.search_input)).perform(typeText("运动鞋"))
onView(withId(R.id.search_button)).perform(click())

如果 home_search_bar 这个 ID 在新版本中被重命名或层级发生变化,这条测试就废了。工程实践中常见的 Page Object 模式 能缓解耦合——把页面元素封装为对象——但本质上仍然是"定位控件 → 操作控件"的脚本范式。UI 结构的根本性重构面前,Page Object 也无能为力。

2.2、痛点二:Android 写一遍,iOS 再来一遍

你的 App 有 Android 和 iOS 两个版本,业务逻辑完全相同,但需要维护两套独立的测试代码:

平台 测试框架 定位方式 断言 API
Android Espresso / UIAutomator withId() / withText() check(matches(...))
iOS XCUITest buttons["Login"] / AccessibilityIdentifier XCTAssert(...)

如果再加上 Flutter(Skia 自渲染,完全绕过原生视图树)、小程序(另一套 DOM 结构)、鸿蒙(ArkUI),维护成本是平台数量的乘法而非加法。

更致命的是,同一个功能在不同平台的 UI 实现可能不同。比如 Android 上"搜索"是首页顶部一个可直接输入的文本框,iOS 上是一个搜索图标,点击后跳转到独立的搜索页——操作步骤都不一样,控件映射根本映不上。

2.3、痛点三:只能查"心跳",不能做"体检"

传统自动化测试的判定标准(术语叫 Test Oracle)几乎只有一条:App 有没有崩溃(Crash)。

但 Crash 只是冰山一角。真正影响用户体验的缺陷往往是非崩溃功能性 Bug:

  • 搜索"iPhone",结果全是 Android 手机壳——搜索逻辑错了,但 App 没崩溃。
  • 使用"满 100 减 20"优惠券后,总价没变——支付逻辑错了,但 App 没崩溃。
  • 切换到英语,半数界面仍是中文——国际化不全,但 App 没崩溃。
  • 商品详情页的图片加载失败,显示灰色占位图——数据异常,但 App 没崩溃。

这些功能性缺陷,传统的 Monkey、Stoat、Sapienz 一个都发现不了。因为它们压根不知道"搜索 iPhone 应该出现 iPhone 商品"——它们不理解业务语义。

2.4、三个痛点的共同根因

仔细看这三个痛点:

  1. 脆弱定位 → 不理解"搜索栏搬到浮层里了,但功能没变"
  2. 跨端鸿沟 → 不理解"Android 和 iOS 的搜索入口不同,但业务意图相同"
  3. Oracle 缺失 → 不理解"搜索 iPhone 应该返回 iPhone 商品"

它们都指向同一个根因:传统测试工具不理解自然语言语义。

这正是大语言模型(LLM)最擅长的领域。


3、传统方法是怎么走到瓶颈的

在进入 LLM 之前,有必要快速回顾传统 GUI 测试的三个阶段,理解为什么走到了瓶颈。

3.1、阶段一:随机模糊测试(2008-至今仍在用)

代表工具:Android Monkey。

原理极其简单——向 App 注入随机的触摸、滑动、按键事件。优势是零配置、即开即用,适合冒烟测试。但问题也很明显:

  • 覆盖率极低:随机点击走不到深层功能。如果某个功能需要"先登录 → 再搜索 → 再加购物车 → 再结算"四步操作,随机策略命中这个序列的概率约等于零。
  • 无法生成有意义的输入:注册页面需要填手机号,Monkey 只会输入乱码。
  • 发现的 Bug 无法复现:随机序列难以确定性重放。

3.2、阶段二:基于模型的系统遍历(2016-2022)

代表工作:Stoat[4]、Sapienz[5]。

思路是用状态转移图(State Transition Graph, STG) 建模 App 的 GUI 状态空间——每个页面是一个节点,每次操作是一条边——然后用 DFS/BFS 或进化算法系统遍历。

1
2
3
4
5
6
          点击"搜索"              点击"结果1"
[首页] ──────────▶ [搜索结果页] ──────────▶ [商品详情]
  │                                            │
  │ 点击"我的"                     点击"加购物车"│
  ▼                                            ▼
[个人中心]                                  [购物车]

Stoat 用两阶段策略(先随机探索建模,再基于模型引导遍历),显著提升了覆盖率。Sapienz 更进一步,将覆盖率最大化建模为多目标优化问题。

但这一代方法有两个致命限制:

  1. 状态爆炸:复杂 App 的 GUI 状态可达数千个,遍历时间呈指数增长。
  2. 文本输入黑洞:DFS/BFS 碰到文本框就卡住了——“请输入搜索关键词”,遍历算法不知道该输什么。研究表明,真实 App 中约 30% 的功能分支隐藏在文本输入之后[1]。这意味着将近三分之一的功能,遍历算法压根触碰不到。

3.3、阶段三:手写脚本 + Page Object(工业界主流)

这是当前工业界的主流实践:QA 工程师手动编写测试脚本,通过 Page Object 模式管理页面元素。

1
2
3
4
5
6
7
class SearchPage:
    search_input = (By.ID, "search_bar")
    search_button = (By.ID, "search_btn")
    
    def search(self, keyword):
        self.find(self.search_input).send_keys(keyword)
        self.find(self.search_button).click()

Page Object 让脚本的可维护性好了很多——UI 变了只需改 Page Object 类,不用改测试逻辑。但它的本质仍然是:人工编写 → 人工维护 → 平台绑定。当你有 500 条测试用例、4 个平台要支持、每两周一次版本迭代时,维护成本就是一笔巨大的"技术债"。

3.4、小结:传统方法的演进逻辑

1
2
3
4
5
6
7
随机点击(Monkey)
    ↓ "能不能别乱点,有策略地走?"
系统遍历(Stoat / Sapienz)
    ↓ "遍历走不到的功能怎么办?文本框填不了怎么办?"
手写脚本 + Page Object
    ↓ "维护不过来了……"
     ???

三个阶段的演进逻辑是"让机器更聪明地点击",但始终没能跨越 “理解用户意图” 的鸿沟。2023 年,LLM 的出现为这个鸿沟提供了桥梁。


4、LLM 第一次"拿起手机"

4.1、一个关键洞见

2023 年,多个研究团队几乎同时意识到了一件事:

LLM 天然具备三种传统测试工具缺失的能力:

  1. 理解自然语言——能"读懂"页面上的文字和按钮含义
  2. 生成有意义的文本——知道搜索框里应该输"运动鞋"而不是乱码
  3. 多步推理——能规划"先登录 → 再搜索 → 再加购物车"的操作路径

如果把 App 当前页面的信息"翻译"成自然语言告诉 LLM,然后让 LLM 决定"下一步做什么"——这不就是一个自动化的测试工程师吗?

4.2、从 GUI 树到 Prompt:那个"翻译"是怎么做的?

上一节说"把页面信息翻译成自然语言",这句话听起来理所当然,但具体怎么翻译,直接决定了 LLM 能不能"看懂"屏幕。

这条管线分三步:获取 → 过滤 → 序列化。

4.2.1、第一步:从手机获取原始 GUI 树

Android 上的标准做法是通过 UIAutomator 导出当前屏幕的视图层次结构:

1
2
adb shell uiautomator dump /sdcard/ui_dump.xml
adb pull /sdcard/ui_dump.xml

导出的是一棵 XML 树,每个节点对应屏幕上一个控件。以一个购物 App 的搜索页为例(简化后):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
<hierarchy rotation="0">
  <node class="android.widget.FrameLayout" bounds="[0,0][1080,1920]">
    <node class="android.widget.LinearLayout" resource-id="com.shop:id/toolbar">
      <node class="android.widget.EditText" resource-id="com.shop:id/search_bar"
            content-desc="搜索商品" clickable="true" bounds="[20,60][900,180]"/>
      <node class="android.widget.Button" text="搜索"
            clickable="true" bounds="[920,60][1060,180]"/>
    </node>
    <node class="android.widget.RecyclerView" scrollable="true">
      <node class="android.widget.TextView" text="运动鞋" clickable="true"/>
      <node class="android.widget.TextView" text="耳机" clickable="true"/>
    </node>
    <node class="android.widget.LinearLayout">
      <node class="android.widget.TextView" text="首页" clickable="true"/>
      <node class="android.widget.TextView" text="购物车" clickable="true"/>
      <node class="android.widget.TextView" text="我的" clickable="true"/>
    </node>
  </node>
</hierarchy>

每个 <node> 的属性中,对 LLM 有价值的信息分布并不均匀:

属性 含义 对 LLM 的价值
text 控件显示的文字 最高——LLM 理解语义的核心依据
content-desc 无障碍描述(给屏幕阅读器准备的) 高——图标类控件的语义全靠它
class 控件类型(Button / EditText / TextView) 高——区分"按钮"和"输入框"
clickable / scrollable 是否可交互 高——知道哪些控件能操作
resource-id 开发者定义的 ID 中——有时有语义(search_bar),有时是乱码
bounds 屏幕坐标 [左,上][右,下] 用于执行——告诉系统"点哪里"

iOS 上等价物是 XCUITest 的 Accessibility Snapshot,数据结构类似但格式不同(JSON 而非 XML)。

4.2.2、第二步:过滤噪声节点

一个中等复杂页面的原始 XML 可能有 200–500 个节点。其中大量是纯布局容器(FrameLayout、LinearLayout)、不可见的占位元素、装饰性分割线——这些对 LLM 完全无用,但会消耗 Token 并稀释注意力。

过滤规则很直觉:

  • 不可见的节点 → 丢弃
  • 纯布局容器(无 text、无 content-desc、不可交互)→ 丢弃
  • 有文字、有描述、或可交互 → 保留

过滤后,上面那棵树从十几个节点精简到六七个有意义的控件。

4.2.3、第三步:序列化为 LLM 可读的文本

这是三个工具的核心技术差异之一——过滤后的结构化数据,用什么格式喂给 LLM。

DroidBot-GPT 用编号列表——最简洁:

1
2
3
4
5
6
7
8
Current screen has the following UI elements:
[1] EditText "搜索商品" [clickable]
[2] Button "搜索" [clickable]
[3] TextView "运动鞋" [clickable]
[4] TextView "耳机" [clickable]
[5] TextView "首页" [clickable]
[6] TextView "购物车" [clickable]
[7] TextView "我的" [clickable]

LLM 回复 [1] type "运动鞋" → 系统通过编号找到对应控件的 bounds 坐标 → 调用 adb shell input tap 执行点击或输入。简洁、Token 消耗低、回复格式可控,但丢失了控件的层级和空间关系。

GPTDroid 用自然语言描述——走得更远:

1
2
3
4
当前是购物 App 的搜索页。页面顶部有一个搜索输入框,
提示文字为"搜索商品",旁边有一个"搜索"按钮。
搜索框下方显示了搜索历史标签:"运动鞋"、"耳机",均可点击。
页面底部有三个导航 Tab:首页、购物车、我的。

这个转换靠模板填充 + 启发式规则实现:根据 class 选描述模板(EditText → “输入框”,Button → “按钮”),再结合 bounds 坐标推断空间位置(“顶部"“下方"“底部”)。LLM 更容易理解控件之间的语义关系(“搜索框旁边有搜索按钮”),但 Token 消耗更高,且自然语言的模糊性增加了回复解析难度。

DroidAgent 用结构化 JSON——取中间方案:

1
2
3
4
5
6
7
8
{
  "activity": "com.shop.SearchActivity",
  "widgets": [
    {"id": 1, "type": "input", "hint": "搜索商品", "interactable": true},
    {"id": 2, "type": "button", "text": "搜索", "interactable": true},
    {"id": 3, "type": "text", "text": "运动鞋", "interactable": true}
  ]
}

结构清晰,LLM 回复也容易解析成程序指令。

三种策略的取舍本质上是 Token 效率 vs. 语义丰富度 的权衡:

序列化策略 Token 效率 语义丰富度 回复可解析性 采用者
编号列表 高 低 高 DroidBot-GPT
自然语言 低 高 低 GPTDroid
结构化 JSON 中 中 高 DroidAgent

4.2.4、这条管线暴露的一个关键限制

为什么要把这个翻译过程单独拿出来说?因为它直接暴露了一个容易被忽视的前提:LLM 的理解质量,上限卡在 GUI 树中语义信息的完整度。

如果一个 ImageButton 没有设置 content-desc,LLM 看到的就是"一个图片按钮(无描述)"——它无法判断这是"搜索"“返回"还是"分享”。如果一个自定义控件没有暴露标准的 Accessibility 属性,它在 GUI 树中可能是一个空节点,甚至完全不存在。

这意味着两件事:

  1. 开发者做的无障碍适配越完整,LLM 测试效果越好。 一份本来是给视障用户准备的 content-desc,现在成了 LLM 理解页面的关键信号。好的 Accessibility 标注同时服务了两个"不看屏幕的用户”——屏幕阅读器和 LLM。

  2. WebView 和 Flutter 等自渲染框架在这里有天然劣势。 Flutter 的 Skia 引擎完全绕过了原生视图树,UIAutomator dump 出来的 XML 里可能只有一个巨大的 SurfaceView 节点——所有按钮、文字、输入框的信息全部丢失。这也是第五节"挑战四"要展开讨论的问题。

4.3、GPTDroid:把 GUI 测试变成一场对话

2024 年发表于 ICSE(软件工程最顶级学术会议)的 GPTDroid[1] 把这个想法做到了极致。

4.3.1、核心思路

GPTDroid 提出了一个极富洞察力的类比:GUI 测试就像一场对话。 App 展示当前页面(“我长这样”),LLM 回复应该做的操作(“那我点这个按钮”)。

每一轮交互是这样的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
┌──────────────────────────────────────────────┐
│ 系统:当前页面信息                               │
│                                               │
│ "当前是购物 App 的搜索页。页面包含:             │
│  - 顶部搜索栏,提示文字'搜索商品'                │
│  - 一个'搜索'按钮                               │
│  - 搜索历史列表(运动鞋、耳机、充电宝)          │
│  - 底部导航:首页 | 分类 | 购物车 | 我的"        │
└──────────────────────┬───────────────────────┘
                       │
                       ▼ LLM 推理
┌──────────────────────────────────────────────┐
│ LLM 回复:                                     │
│ "在搜索栏中输入'运动鞋',然后点击'搜索'按钮。"    │
└──────────────────────────────────────────────┘

这里的关键创新:LLM 接收的是自然语言描述,而不是 XML 格式的控件树。这意味着 LLM 是在"阅读"页面而非"解析"页面——就像一个人类测试员看到屏幕后做出的判断。

4.3.2、功能感知的记忆提示(Memory Prompting)

如果只是简单地让 LLM “看一页、做一步”,LLM 很快就会原地打转——因为它不记得之前做过什么。这就像一个失忆的测试员,每次打开 App 都从头开始。

GPTDroid 的核心技术创新是引入了功能感知的记忆机制。每次请求 LLM 时,Prompt 中包含三层信息:

第一层:当前页面信息

1
2
3
4
5
6
7
当前页面:商品详情页
可操作控件:
  [1] 商品图片(可点击查看大图)
  [2] "加入购物车" 按钮
  [3] "立即购买" 按钮
  [4] "收藏" 按钮
  [5] 返回按钮

第二层:已探索的功能列表(避免重复)

1
2
3
4
已测试的功能路径:
  ✓ 搜索商品 → 查看商品详情
  ✓ 查看购物车(空)
  ✓ 查看个人中心(未登录状态)

第三层:未探索的功能提示(引导深入)

1
2
3
4
5
尚未测试的功能:
  ✗ 加入购物车
  ✗ 用户登录/注册
  ✗ 下单结算
  ✗ 商品收藏

这相当于给 LLM 一个"测试备忘录”,引导它去探索未覆盖的功能分支,而不是在已经测过的功能上反复打转。

4.3.3、实验数据

GPTDroid 在 86 个 Google Play 热门 App 上的实验结果:

对比方法 Activity 覆盖率差距 GPTDroid 独有发现的 Crash Bug
vs. Monkey GPTDroid 高 32% ——
vs. Stoat GPTDroid 高 19% ——
vs. Humanoid GPTDroid 高 13% ——
总计独有 Bug —— 31 个(部分已被开发者确认修复)

这个数据值得细说:

覆盖率提升 32% 意味着 GPTDroid 能走到 Monkey 到不了的深层页面。差距主要来自两个方面:(1)GPTDroid 能生成有意义的文本输入,打开了那"30% 的隐藏功能分支";(2)记忆机制引导 LLM 持续探索新区域,而非在已知区域打转。

31 个独有 Crash Bug 意味着这些 Bug 是所有传统工具(Monkey、Stoat、Humanoid、ComboDroid)都没发现的。这些 Bug 藏在需要特定输入或特定操作序列才能触发的深层路径中——正是 LLM 语义理解能力的"杀手级"应用场景。

4.4、DroidBot-GPT:最小可行产品的力量

几乎和 GPTDroid 同期出现的 DroidBot-GPT[2] 走了一条更"简约"的路线。它的架构一句话就能说清:

DroidBot(已有的 GUI 遍历工具)+ GPT API 调用 = DroidBot-GPT

就这么简单。复用 DroidBot 已有的 GUI 状态提取能力,把 GUI 树序列化成文本,问 GPT:“现在页面是这样的,下一步做什么?”

DroidBot-GPT 的价值不在于架构多精妙,而在于它验证了一个至关重要的假设:

通用的、未经微调的 LLM,仅凭自然语言提示,就能理解移动端 GUI 的语义并生成有效的测试操作。

在此之前,很多人怀疑这一点——LLM 是在互联网文本上训练的,它怎么可能理解 Android 的 XML 视图层级?DroidBot-GPT 用最低的实现成本证明了:能,而且效果不错。

这个"最小可行产品"降低了整个领域的准入门槛——它告诉所有人:你不需要训练专用模型、不需要构建复杂管线,只需要把 GUI 信息"翻译"成自然语言,就能利用 LLM 的推理能力做测试。

4.5、DroidAgent:从"被动回答"到"主动规划"

GPTDroid 和 DroidBot-GPT 的 LLM 都是被动的——系统给它看当前页面,它回答下一步做什么。这就像一个测试新手,领导指哪打哪,从不主动想"我接下来该测什么"。

DroidAgent[3] 把 LLM 升级为一个"高级测试工程师"——它会自主生成高层次的测试目标。

4.5.1、两层决策架构

DroidAgent 的核心是一个两层决策系统:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
┌──────────────────────────────────────────┐
│             战略层(Strategic)            │
│                                          │
│  LLM 自主生成测试意图:                     │
│  "我接下来要测试用户注册流程"                │
│  "我接下来要测试购物车的编辑功能"            │
└──────────────────┬───────────────────────┘
                   │ 指导
                   ▼
┌──────────────────────────────────────────┐
│             战术层(Tactical)             │
│                                          │
│  根据当前意图 + 当前页面,给出具体操作:     │
│  "点击底部'我的'tab → 点击'注册'按钮       │
│   → 输入手机号 → 获取验证码 → ……"          │
└──────────────────────────────────────────┘

战略层负责"想"——决定测什么。它基于 App 的功能描述(从应用商店获取)和已探索的功能列表,推理"这个 App 还有哪些功能我没测过",然后生成新的测试意图。

战术层负责"做"——在具体页面上执行操作。它结合当前意图和页面信息,逐步推导操作序列。

4.5.2、为什么这很重要?

DroidAgent 代表了从"工具"到 “智能体(Agent)" 的跃迁:

维度 GPTDroid(工具) DroidAgent(智能体)
目标来源 由记忆提示隐式引导 LLM 自主生成
决策层次 单层(下一步做什么) 双层(先想测什么,再想怎么做)
测试的"目的性” 中等 高

从 DroidAgent 开始,我们不再称这些系统为"测试工具",而是称为 “测试智能体(Testing Agent)"——它们有目标、有规划、有执行能力。


5、这三个工作的技术脉络

把三个开创性工作放在一起,可以清晰地看到技术演进的脉络:

维度 DroidBot-GPT GPTDroid DroidAgent
时间 2023.04 2023.10(ICSE 2024) 2023.11
定位 概念验证 完整系统 进阶架构
LLM 角色 逐步决策者 带记忆的决策者 自主规划者
页面理解 GUI 树 → 文本 GUI 树 + 自然语言 GUI 树 + App 描述
记忆机制 无 功能感知记忆 意图级别记忆
核心贡献 验证可行性 覆盖率突破 Agent 范式引入

它们共同完成了三个范式转换:

1
2
3
控件 ID 匹配      ──▶  自然语言语义理解
随机/遍历策略      ──▶  语义驱动的有目标探索
被动执行工具       ──▶  主动规划的智能体

6、第一代 LLM 测试方法的四个挑战

尽管进展巨大,这一批方法仍面临四个共同挑战:

6.1、挑战一:每步都要调 LLM,太慢太贵

假设一次测试需要 300 步操作,每次 LLM 调用耗时 3 秒、费用 $0.01:

  • 时间:300 × 3 = 15 分钟(Monkey 只需几秒完成 300 次操作)
  • 费用:300 × $0.01 = $3/次

这个问题有解。GraphDroid 提出了一种"异步架构”,将 LLM 调用量降低了 90%——怎么做到的,值得单独展开。

6.2、挑战二:只在 Android 上验证,iOS / Flutter 怎么办?

这批方法都在 Android 上做实验。跨平台迁移能力没有被验证。

IntentDroid 给出了一个思路:把测试意图和平台执行解耦——一次提取意图,多端复用。

6.3、挑战三:Oracle 仍然只是 Crash 检测

“搜索结果对不对"“价格计算对不对”——它们判断不了。

已经有人在攻克这个问题了。VisionDroid 尝试通过"看截图"发现非崩溃功能 Bug,LogiDroid 则走了自动生成业务逻辑断言的路线——两个方向都值得深挖。

6.4、挑战四:依赖 GUI 树,WebView/Flutter 自渲染时信息残缺

多模态 LLM 提供了一条绕过路径:不解析 GUI 树,直接"看"屏幕截图来理解页面。


7、总结

本文回答了两个问题:

“传统测试为什么越做越痛?" → 因为机器不理解语义。控件 ID 会变、平台会不同、业务规则不在代码里——但语义是稳定的。

“LLM 如何破局?" → 三个工作渐进式地回答了这个问题:

  • DroidBot-GPT 证明了 LLM 能做到
  • GPTDroid 证明了 LLM 能做得好(覆盖率 +32%,发现 31 个独有 Bug)
  • DroidAgent 证明了 LLM 不仅能执行,还能规划

但故事没有在这里停下。LLM 测试正在向两个更深的方向突破——跨平台迁移和视觉理解。如果 AI 不读 XML 控件树,而是直接"看"屏幕截图,它能发现什么样的 Bug?如果一套测试意图能在 Android、iOS、Flutter 上分别运行,跨端测试维护的噩梦是否就此终结?这两个问题的答案,比想象中更有趣。


参考文献

[1] Zhe Liu, Chunyang Chen, Junjie Wang, et al. “Make LLM a Testing Expert: Bringing Human-like Interaction to Mobile GUI Testing via Functionality-aware Decisions” (GPTDroid). ICSE 2024. arXiv:2310.15780.

[2] Hao Wen, Hongming Wang, Jiaxuan Liu, Yuanchun Li. “DroidBot-GPT: GPT-powered UI Automation for Android”. arXiv preprint, 2023. arXiv:2304.07061.

[3] Juyeon Yoon, Robert Feldt, Shin Yoo. “Intent-Driven Mobile GUI Testing with Autonomous Large Language Model Agents” (DroidAgent). arXiv preprint, 2024. arXiv:2311.08649.

[4] Ting Su, Guozhu Meng, Yuting Chen, et al. “Guided, Stochastic Model-Based GUI Testing of Android Apps” (Stoat). ESEC/FSE 2017.

[5] Ke Mao, Mark Harman, Yue Jia. “Sapienz: Multi-objective Automated Testing for Android Applications”. ISSTA 2016.