Page 112 - 《软件学报》2025年第5期
P. 112
2012 软件学报 2025 年第 36 卷第 5 期
组件则共有 11 个回调函数, 如果开发者没有正确处理这些回调函数, 会导致应用在设备旋转、应用切换等复杂交
互中崩溃. 因此, 在本文中我们也将与组件生命周期变化相关的事件标记为重要事件, 包括应用切换事件、设备旋
转事件、返回按键事件. 在实现上, 设备旋转事件、环境改变事件均可以通过测试脚本中事件格式解析的方式直
接进行标记, 应用切换事件可通过状态跳转图中事件前后应用是否改变进行检测并标记.
此外, 某些操作事件对应用中变量进行修改, 这些修改虽然没有直接反映到 GUI 界面变化上, 但却会对应用
逻辑产生影响, 继而触发程序崩溃. 例如图 1 序列 (b) 中操作事件 e 113 到 e 115 修改了 server 地址, 这个地址格式不
正确时软件应用会崩溃. 为了检测这种类型的操作事件, 我们对崩溃 stack trace 进行分析, 获取崩溃错误类型、出
错函数、错误信息, 并以出错函数为目标对应用进行后向数据流分析 (backward analysis) [28] , 获取对出错函数调用
产生影响的相关变量及变量值, 作为崩溃错误关键词, 对操作事件本身则通过 GUI 界面分析获取其作用到的控件,
得到控件上属性、内容相关关键词, 可以通过属性 text、resource-id、content-desc 等获取关键词, 而且平凡最短路
T s 的搜索也需遵循原测试序列中的事件时序. 最后通过对两类关键词进行相似度分析从而判断某操作事件是
径
否应该被标记. 在本工作中, 采用轻量分析策略, 仅对 IllegalArgumentException、ArrayIndexOutOfBoundsException、
NullPointerException 等几种与数据依赖最相关的崩溃错误进行依赖分析, 忽略了 NoClassDefFoundError、
IllegalStateException 等仅与程序正确实现与否、程序栈状态是否正确等对数据流不敏感的错误, 并且采用严格关
键词匹配策略, 只有当某一关键词完全匹配时才对操作事件进行标记, 这么做的原因是控制被标记的重要事件数
量, 避免过多无关事件被标记从而影响后续最短路径搜索效率.
3.4 最短测试路径搜索
T 的搜索, 其具体思路如算法 2 所示. 算法首
′
给定状态跳转图, 我们在图上进行起点到终点之间的最短路径
先利用深度遍历的方式找到平凡最短路径 T s [2] , 如果其能正确触发程序崩溃, 则直接终止搜索并将 T s 作为找到
的路径返回 (第 1–4 行). 若 T s 无法正确触发程序崩溃, 算法检测在跳转图中所有以 T s 上的节点为起止点的环路,
并对其重要性程度进行标记 (第 5, 6 行). 接下来算法将进行不同重要性层次上的环路集约减, 由于能影响程序崩
溃是否触发的环路 (在本文中我们定义为必要环路) 更可能被标记为高重要性环路, 因此我们在约减时遵循重要
性由高到低的顺序以便提升搜索效率 (第 7 行), 变量 level 代表了搜索算法的起始层次, 只有在所有高重要性的环
路均无法正确触发程序崩溃时, 才会进入低重要性环路集约减, 举例来说, 当 level 为 MINOR 时, 说明搜索算法在
IMPORTANT 、 NORMAL 层次上均已失败, 要寻找的最短路径 T s 中包含了 MINOR 必要环路.
算法 2. 最短测试路径搜索.
1. Function search( G )
2. T s ← shortestPath( G ; //获取平凡最短路径
)
3. if test(T s ) = X then
4. return T s ;
G,T s ; // 检测状态跳转图中所有环路
5. L ← findLoops( )
)
6. L ← coloring( G,L ; // 对所有环路进行重要性标记
7. for level in {IMPORTTANT,NORMAL,MINOR} do
′
8. level ← level; // 起始搜索层次
′
L ′ level 重要性低的必要环路
9. changes ← ∅; // 存放所有比
′
10. while level ⩽ IMPORTANT do
′ ′ ; // 构建基础测试路径
11. T base ← T s + filterLoopsGreaterThan( L,level ) +L
changes
level 的环路均为冗余环路
′
12. if test(T base ) = X then // 说明重要性为
′
13. T base ← T base − filterLoopsGreaterThan( L,level ; // 更新基础测试路径
)
test(T base ) = X then // 说明更高重要性的所有环路均为冗余环路
14. if