自学 UiAutomator 并使用已快一年了,也独自完成了项目中的 800 条自动化测试用例的编写,其中坑坑洼洼亦不知多少,更不消说 UiAutomator 本身就有 Bug 了.现如今也来说说一点小想法.这里我主要想讲一下,最近在编写自动化测试 PC 端工具时,所想到的一些点子.

我的想法就是通过 UiAutomator 本身的 dump 命令,来抓取手机当前页面的 xml 档,这个 xml 档里面有存储手机当前页面的属性及坐标等.接着通过 shell 脚本命令来解析或过滤出我们想要点击的属性的坐标值来,最后通过 sendevent 的方式来实现:点击/长按/滑动 (Swipe)/双击/拖拽 (Drag)/多点点击等操作.

阅读前提:

  1. 读者需要掌握 uiautomator 的基本用法
  2. 读者需要掌握 shell 脚本的基本用法,以及 grep 与 sed 的常用方法

首先,我们需要借助 UiAutomator 抓取手机当前页面的配置信息,我们在 DOS 命令行中,执行 adb shell uiautomator dump 时,会自动生成一份文件,并存储在手机的 SD 卡根目录中,名为:window_dump.xml.读者可以将它复制到电脑上来查看,其实这个文件和我们在电脑上借助 Android SDK 中,uiautomatorviewer.bat 来察看手机当前页面的属性等值的方法是一样的.

REM 这里是DOS命令行,REM为DOS命令行注释,请知悉
REM 这里使用的是小米手机,Android Version: 4.4.4
C:\Users\Administrator>adb shell uiautomator dump
UI hierchary dumped to: /storage/emulated/legacy/window_dump.xml

那抓出来的档案是可以在电脑上来查看的,形如:

<?xml version="1.0" encoding="UTF-8" standalone="true"?>
<hierarchy rotation="0">
<node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="com.miui.notes" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][720,1280]">
<!--这里提注释,内容太多,抱歉,不便全列,省略若干字哈 -->
</hierarchy>

接着,这里我们介绍如何借助强大的 Shell 脚本,来抓取/过滤出我们想要的东东,

getCoordinateByAttribution()
{

#这里我们定义了一个instance,它的灵感是来自UiAutomator中的同名操作.意思是在当前页面下,有n个一模一样的属性,我们不好区分时,使用instance来指出我们需要点击的是第一个还是第n个属性.默认点击第一个.
instance=""
instance=${instance:=$2}
instance=${instance:=1}

uiautomator dump
#这里借助了busybox工具,至于什么是busybox工具以及如何安装,此处暂不讲,读者可以先行百度,若有困难,再说.
#这里借助grep命令,来过滤出我们需要点击的属性,个人认为此方法比UiAutomator这个工具本身要方便一些.UiAutomator本身做了很多的区别,比如text,descrption,resourceId等等.
temp=`cat /mnt/sdcard/window_dump.xml|busybox sed 's/>/\n/g'|busybox grep "$1"|busybox sed -n {$2}p`
temp=`echo ${temp%]\"*}`
temp=`echo $temp|busybox awk '{print $NF}'`

#此处我们作一个判断,如果temp的值不等空串的话,我们认为找到了我们需要查找的属性,并作进一步的处理
if busybox test ! "$temp" == ""
then
temp=`echo ${temp/bounds=/}`
temp=`echo $temp| busybox sed 's/"//g'| busybox sed 's/\[//g'| busybox sed 's/\]/\n/g'`
p1=`echo $temp|busybox awk '{print $1}'`
p2=`echo $temp|busybox awk '{print $2}'`
#定义四个变量,用例存储找到的属性的四个坐标值
p1x=`echo ${p1%,*}`
p1y=`echo ${p1#*,}`
p2x=`echo ${p2%,*}`
p2y=`echo ${p2#*,}`

let centerX=$p1x/2+$p2x/2
let centerY=$p1y/2+$p2y/2
else
#这里是查找属性失败时的动作
echo `date +%m-%d-%H-%M-%S` getCoordinateByAttribution $1 failed >> /mnt/sdcard/log.txt
#screencap是android自带的可以抓图的命令,这里加上了时间而已
screencap -p /mnt/sdcard/"`date +%m-%d-%H-%M-%S`".png
fi
}

这个函数如何调用呢?容我举例说明,我们可在 shell 脚本中执行以下命令来调用它.

#这是一个查找点击text属性的例子,这里加上双引号是因为,即使字串中有空格时,也不会被当成两个参数来处理
getCoordinateByAttribution "text" 1
#这是一个查找点击description属性的例子
getCoordinateByAttribution "description" 1
#这是一个查找点击resourceId属性的例子
getCoordinateByAttribution "resourceId" 1
#如果有三个一模一样的resourceId属性,而我们需要点击第三个属性的话
getCoordinateByAttribution "resourceId" 3

OK,既然已查找到属性,如何点击它呢?这里我们借用 android 自带的 sendevent 方法,当然你也可以使用 input 命令来点击,因为坐标值我们已经获取到了.
这里还是用小米 2 移动定制手机为例,

#这里定义了点击的shell函数
Tap()
{
sendevent /dev/input/event0 3 57 1
sendevent /dev/input/event0 3 53 $1
sendevent /dev/input/event0 3 54 $2
sendevent /dev/input/event0 1 330 1
sendevent /dev/input/event0 0 0 0
sendevent /dev/input/event0 3 53 $1
sendevent /dev/input/event0 3 54 $2
sendevent /dev/input/event0 0 0 0
}
#结合前面所述,我们只需点击对应坐标便可
Tap $centerX $centerY

以上便是小可今天花了一个小时,写出来的一点东东了,可能有些地方不恰当,敬请批评指正,感谢!
本来还有一些感言什么的,感觉写出来,也是无甚趣味,呵呵,不写也罢.第一次发贴,诚惶诚恐.


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