对于测试人员, UI 遍历已经很普遍了,比如说 Monkey, UICrawler 等等,都可以进行 UI 遍历。那我们怎么按照顺序去遍历一个 app 呢。下面介绍一个 360 开测平台上使用的用 uiautomator 做的 UI 遍历。

实现步骤

需要的参数: 包名, 启动类名,遍历截止类名,遍历时间,遍历总步数,遍历中需要登录的账号,登录密码。

实现思路:

  1. 启动当前的 apk
  2. 添加界面变化监听
  3. dump 界面组件元素
  4. 排列界面组件元素
  5. 比对界面元素
  6. 操作界面组件元素,截图绘制
  7. 遍历结束,停止 UI 遍历

详细说明

步骤 1

启动当前的 apk

初始化参数配置

步骤 2

监听界面变化,这里我们添加 AccessibilityService 进行界面变化的监听,主要监听界面的三个变化,TYPE_WINDOW_STATE_CHANGED, TYPE_WINDOW_CONTENT_CHANGED,TYPE_VIEW_CLICKED 窗口变化,窗口内容变化, 点击事件变化监听。

我们做一些初始化的判断:

1.包名是否正确

// 判断是否监听到了包名
if (null != event.getPackageName()) {
    if (TextUtils.isEmpty(event.getPackageName().toString())) {
        LoggerEx.getLogger().error("包名获取为空, 返回...");
        return;
    }
    if(ClassNameUtils.dumpISDesk(event.getPackageName().toString())) {
        LoggerEx.getLogger().error("任务停止..包名不对应..." + event.getPackageName().toString());
        endTraverse();
        return;
    }
} else {
    return;
}

2.类名是否获取成功

// 获取当前显示界面的类名
String classname = getClassName();
if (TextUtils.isEmpty(classname)) return;

3.软件盘弹出来了,关掉软件盘输入

// 首先把软键盘给关闭掉
if(ViewTraverseTools.getInstance().closeKeyWord()){
    LoggerEx.getLogger().error("软件盘出现...");
    closeKeyBoard(); // 当前软键盘是打开状态,我们要把软件盘给关闭掉
}

步骤 3,4

dump 界面组件元素,我们在这里只 dump 一些我们可以操作的界面元素,比如说可以点击的,可以滑动的界面元素。

在 dump 的过程中,我们可以按照一般的 app 出现的特殊情况进行一个排序,比如列表的话,我们只取在界面范围内的元素,ViewPage ,我们可以优先取出来:

判断 列表在点钱界面有几个子界面可以 dump:

/**
 *  listview item count is show screen
 *
 *  我们判断一下当前界面的listview 有几个子项可点
 */
private int listViewShow(AccessibilityNodeInfo node, int count){
    int numberChildForList = 0;
    for(int i = 0; i < count ; i++){
        if(isInScreen(node.getChild(i))){
            numberChildForList++;
        }
    }
    return numberChildForList;
}

判断当前的控件是否显示在可见屏幕范围内:

保存数据:

步骤 5

比对界面元素,判断当前要操作的组件。

我们怎么比对当前界面操作的元素呢:这里分为两种比对方式

  1. MD5 比对, 在存储的串中,当前操作的 MD5 是否和当前界面生成的 MD5 是否相同。

  2. 比对图片的相似度,每点击一次,比对一个图片相似度,如果存在相同的部分,直接抽取数据进行排列组合生成一个新的 list

步骤 6

操作界面元素

步骤 7

停止 UI 遍历

停止条件: 遍历时间和设置时间相同, 遍历步数和设置的步数相同, 返回手机屏幕界面,遍历结束

// 当主页面的步数小于等于0 ,或者 时间结束,或者
if (mainPage <= 0 || (System.currentTimeMillis() - startTime > allTime)) {
    LoggerEx.getLogger().error("任务停止..操作超出上线...");
    endTraverse();
    return;
}

效果



↙↙↙阅读原文可查看相关链接,并与作者交流