UiAutomator 基于 Uiautomator 2.0 的 App 遍历测试探索

木月 · 2016年01月29日 · 最后由 张斌 回复于 2017年11月21日 · 3494 次阅读

探索目的

因为目前公司的一些情况,任务重,人力紧,现在没有过多的人力投入到自动化脚本的编辑,所有想出一个可以一劳永逸,能够简单便利 App 的测试脚本,完成简答的兼容测试;

目前实现状况

目前基本已经实现,但在使用的过程中,发现还有一些问题:
1、下载页面布局慢,导致执行速度慢
2、需要处理的异常情况过多,比如监控系统弹框等,如果要完美实现这一功能,需要做的优化还有很多
3、便利测试的规则难以完美制定,原因是一个页面可能是分很多 Tabs 的,每个 Tabs 的内容又各不相同,可能需要同一个页面多次获取页面布局信息,导致遍历的时候有可能一些点是过不到了

实现逻辑

简单来讲,设置一个心跳循环,先创建 2 个 JSONObject,一个用于存放 App 页面布局信息(A),一个用于控制页面内容的点击(B),打开 App 后,获取当前页面 Activity 名称,通过 Activity 名称去查看存放 App 页面布局信息的 JSON(A)数据,是否已保存当前页面布局信息,如果未保存,则下载当前页面布局文件,并分析文件,获取到 ResourceID 和 Text 项,将这些元素整合到合并到一起(中间添加必要的元素用于区分),以当前 Activity 名称为 Key 保存到 JSON(A)中,如果当前页面布局信息已经保存,则读取 JSON(A)数据获得当前页面的元素,并逐次执行,这里同样适用 JSON(B)中 Key 同为当前 Activity 名称的 Value 值来控制点击内容,Value 值一开始赋予当前当前 Activity 元素的个数,执行一个之后,则执行-1,并做一些控制,如果当前页面连续三次点击错误(定位失败),则重新获取下布局信息,覆盖之前的布局文件;

简单代码实现

private Handler handler = new Handler();
private Runnable myRunnable = new Runnable() {
        public void run() {
                  String Activity  获取当前页面Activity
                  if(!JSON_A.has(Activity){
                           获取当前文件布局信息dumpWindowHierarchy()
                            解析部分文件并将获得的元素放到key 为Activity的Value
                  }
                  String Activity_element = JOSN_A.getString(Activity);
                  String[] element  Activity_element.split(区分元素添加的特殊字符);
                 JSON_B.put(Activity,element.length);

                 //转换成点击操作
                 1从后往前依次取出元素并做判断后执行点击操作
                  如果成功则将JSON_B的Activity的值-1;
                  如果失败则将另一个统计失败次数的int index+=1;
                 if(index==3){
                        重新获取元素
                 }
         }
         handler.postDelayed(this, 50);
}
handler.post(myRunnable);
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
共收到 10 条回复 时间 点赞

感谢,一直找不到遍历所有界面的方法,学习到了

代码貌似不太完整啊. 想全部遍历需要自己维护一个树形结构才行. 不然容易点过了某个 tab 导致错过当前 tab 里面的内容.

@seveniruby 只是上传了一个思路,要是真做好,优化的地方太多了,很多逻辑都要考虑,目前实际运行中还是不顺畅;
元素就是通过 JSON 数据维护的,一个页面的元素通过简单合并作为该页面 Activity 的 Key 的值

@niuniudd ,思路有了,但实际转换成可以公司推广用的,还有很多路啊

#4 楼 @350705144 总算先有个入门的思路了

又见遍历..上次说整理的结果一直到现在还没有弄。整个遍历的困难点就在于 “当前页面是否来过,从哪里开始”。 LZ 所说的 “以当前 Activity 名称为 Key 保存到 JSON(A)中,如果当前页面布局信息已经保存,则读取 JSON(A)数据获得当前页面的元素,”, 实际使用中会碰到完全一模一样的 activity, 则无法根据布局来判断页面是否保存过。 正如@seveniruby所说, 做树形结构是比较稳妥的方案,缺点是判断比较多,实现起来不是简单的迭代,最后落地跑起来发现运行速度比较慢。个人比较推荐根据自己的模型来计算当前页面 hashcode,作为 key 将个页面对象保存在一个容器中,每次发生页面变化则重新计算 hashcode 来判断当前是新 activity 还是旧 activity。

#6 楼 @tbya activity 做 md5,用 md5 比较

dumpWindowHierarchy 的效率太低了。尝试使用反射,通过 AccessibilityNodeInfo 获取控件树信息

@marker 可以不可以详细说明一下通过 AccessibilityNodeInfo 获取控件树信息的方式啊

tbya 回复

当前界面的实现技术除了 activity,还有 fragment。单纯用 activity 作为 key 不太合适。往往一个 activity 可能会承载好几个界面的展示!所以我觉得映射关系应该是 activity-window-树 。但是这三种两两的映射关系找不到可以关键的字段!

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册