Android自动化测试UiAutomator

##UIAutomator

  1. UiAutomator简介

    1. UI测试的重要性,在这里就不赘述了,使用UIAutomator可以很好的完成这个任务了。
      UIAutomator包含两个部分,一个uiautomatorviewer,分析UI的工具,一个uiautomator,这个是一个Java库,包含需要的API和相关的执行工具。
    2. 环境要求
      • UIAutomator要求必须要Android SDK Tools>21,
      • Android SDK Platform>16(android 4.1)。
      • JDK version >1.6
  2. 配置编写环境

    1. JDK ,ADT(Android SDK + Eclipse),Ant (在Eclipse中已经包含,如果你使用的是Eclipse的话在Eclipse中直接搜索ant,找到ant所在的目录直接加入到环境变量中.
      省略
  3. 新建测试工程
    1. 在Eclipse中新建一个java工程,包.
    2. 把SDK中platform目录中的android.jar 和 uiautomator.jar 加入到buid path中.
    3. 新建一个测试类,继承UiAutomatorTestCase
    4. 编写测试用例,方法名称必须test开头
    5. 编译运行
  4. 编译运行测试代码

    1. 创建build 文件,-n 需要发布的jar包的名称, -t编译时候使用的SDK的版本在你本地机器的id编号可以通过android list命令获得

      android create uitest-project -n <jars> -t 1 -p <workspace path>
      
    2. 修改build 文件,修改build.xml文件,将第二行的help修改为build

    3. 开始编译

      ant -buildfile <build.xml path>
      
    4. push文件

      adb push <jar file path> /data/local/tmp/
      
    5. 运行测试

      adb shell uiautomator runtest <jars> -c <package name> <class name> [# test name]
      
  5. 运行命令与快速调试

    • adb shell uiautomator runtest -c [options]
字命令 操作参数 描述
< jars > 指定运行的jar包的名称,位于/data/local/tmp/下
runtest -c < classes > 测试一个类下的所有用例格式:package_name.class_name ,多个类用多个-c,如果不指定则运行真个jar包下的所有用例
–nohup 制定此参数,可以断开pc运行测试用例
-e < key> < value> 传入一个键值对到测试程序中,用于一些变化的参数 ,在测试程序用可以使用 Bundle bundle = getParams(); String value = bundle.getString(key);
- 快速调试
    在github中搜索uiautomatorhelper.通过这个可以快速的运行与调试
  1. UiDevice 类
    1. 类介绍
      UiDevice 代表设备状态,可以获得设备的不同属性如屏幕旋转方向,屏幕大小等。还可以执行设备级的操作,如强制横竖屏,按压屏幕与按压各种按键等。
      UiDevice 是单例模式一种方式是UiDevice.getinstance() (推荐) & getUiDevice() (容易产生空指针异常)
    2. 按键与KEYCODE使用,按键常用api
返回值 方法名 描述
boolean pressBack() 模拟短按返回back键
boolean pressDelete() 模拟短按删除delete键
boolean pressEnter() 模拟短按回车键
boolean pressHome() 模拟短按HOME键
boolean pressMenu() 模拟短按返menu键
boolean pressRecentApps() 模拟短按最近使用程序
boolean pressSearch() 模拟短按搜索键
boolean pressKeyCode(int KeyCode,int metaState) 模拟短按键盘代码keycode
boolean pressKeyCode(int KeyCode) 模拟短按键盘代码keycode
KEYCODE 键盘映射码
    1. KeyEvent 按键事件 KeyEvent.KEYCODE_A
    2. META Key: ALT,SHIFT CAPS_LOCK
激活状态 metaState
base META_key未被激活 0
caps SHIFT或CAPS_LOCK被激活时 1
fn ALT被激活 2
caps_fn ALT,SHIFT或CAPS_LOCK同时被激活 3
3. 获取坐标与坐标的点击
    1. click(x,y) 点击x,y的坐标
    2. getDisplayHeight() 获取高度
    3. getDisplayWeight() 获取宽度
4. 拖拽与滑动
    1. 拖拽:将一个组件从一个坐标拖到另一个坐标处.
    2. 滑动:从一个个坐标点到另外一个坐标点.
    3. 步长:从一个坐标点到另外一个坐标点的时间.
    4. 相关API
返回值 API 说明
boolean drag(int startx,int starty,int endx,int endy,int steps) 从一个个坐标点到另外一个坐标点
boolean swipe(Point[] segments,int segmentSteps) 在点阵中滑动,5ms为一步长
boolean swipe(int startx,int starty,int endx,int endy,int steps) 通过坐标滑动屏幕
5. 旋转屏幕
    1. 相关的知识
        - 旋转方向: 4个方向 0度, 90度,180度,270度
        - 重力感应器
        - 固定位置与物理旋转(重力感应器)
    2. 相关的API
返回值 API 说明
void setOrientationLeft() 通过禁用传感器,然后模拟设备向左转,并且固定位置
void setOrientationNatural() 通过禁用传感器,然后模拟设备转到其自然默认的位置,并且固定位置
void setOrientationRight() 通过禁用传感器,然后模拟设备向右转,并且固定位置
void unfreezeRotation() 重新启用传感器和运行物理旋转
boolean isNaturalOrientation() 检测设置是否处于默认旋转状态
int getDisplayRotation() 返回当前的显示旋转,0度,90度180度270度值分别是0,1,2,3
void freezeRotation() 禁用传感器和冻结装置物理旋转在其当前旋转状态
6. 唤醒与关闭屏幕
    1. 相关的API
返回值 API 说明
void wakeup() 模拟按下电源键,如果屏幕是点亮状态则无效
void sleep() 模拟按下电源键,如果屏幕是关闭状态则无效
boolean isScreenOn() 检查屏幕是否是点亮状态
7. 截图与等待空闲
    1. 截图相关的API
返回值 API 说明
boolean takeScreenshot(File storePath) 把当前窗口截图并存储位png默认1.0f的规模和90%质量,参数位file类的文件路径
boolean takeScreenshot(File storePath,float scale, int quality) 把当前窗口截图并存储位png,自定义缩放比例与图片质量
    > storePath:存储路径必须为png格式,
    > Scale: 缩放比例,1.0为原图
    > quality: 图片压缩质量,范围是0-100

2. 等待空闲的API,等待某一个窗口打开或者等待某一个窗口的更新
返回值 API 说明
void waitForIdle(long timeout) 自定义超时等待当前应用处于空闲状态
void waitForIdle() 等待当前应用处于空闲状态,默认等待10s
boolean waitForWindowUpdate(String packageName, long timeout) 等待窗口内容更新时间的发生
8. 获取包名,开启通知栏,快速设置,获取布局文件
    1. 包名
    2. 通知栏
    3. 快速设置
    4. 布局文件
    5.相关的API
返回值 API 说明
void getCurrentPackageName() 获取当前截面的包名
void dumpWindowhierarchy(String filename) 获取当前截面的布局文件,保存在/data/local/tmp/目录下面
boolean openNotification() 打开通知栏
boolean openQuickSettings() 打开快速设置
  1. UiSelector 类

    1. 类介绍
      学习自动化的关键技术就是搜索到界面的 UI组件元素,UiSelector就是代表着一种搜索条件,通过UiSelector可以搜索到界面的各种组件,然后才能进行下一步的操作相应的组件。当匹配到多个元素时返回第一个匹配的元素.

      当工程中出现中的时候需要把整个工程的编码设置成utf-8.

    2. Android的布局与组件以及属性介绍

      1. 布局

        1. 线性布局 LinearLayout
        2. 表格布局 TableLayout
        3. 相对布局 RelativeLayout
        4. 帧布局 FrameLayout
          5.网格布局 GridLayout
        5. 绝对布局 AbsoluteLayout
      2. 属性

        1. 省略…
    3. 四种匹配关系的介绍

      1. 完全匹配(默认)

        new UiSelector().text("123")
        
      2. 包含匹配(Contains)

        new UiSelector().textContains("23")
        
      3. 正则匹配(Matches,包含其他三种匹配)

        new UiSelector().textMatches(".*2.*")
        
      4. 起始匹配(StartWith)

        new UiSelector().textStartWith("12")
        
    4. 节点关系介绍

      1. xml 节点层次关系
    5. 对象搜索-文本与描述
      1. 文本相关的API
返回值 API 说明
UiSelector text(String text) 文本
UiSelector textContains(String text) 文本包含
UiSelector textMatches(String regex) 文本正则
UiSelector textStartsWith(String text) 文本起始匹配
2. 描述相关的API
返回值 API 说明
UiSelector description(String desc) 文本
UiSelector descriptionContains(String desc) 文本包含
UiSelector descriptionMatches(String regex) 文本正则
UiSelector descriptionStartsWith(String desc) 文本起始匹配
6. 对象搜索-类名与包名
    1. 类名相关的API
返回值 API 说明
UiSelector className(String className) 类名
UiSelector classNameMatches(String regex) 正则类名
    > 快速书写方式
    >     1. class.getName方式
    >     2. 完整类名方式:android.widget.LinearLayout
    >     3. 正则方式
    >    4. 常量方式

2. 包名相关的API
返回值 API 说明
UiSelector packageassName(String name) 包名
UiSelector packageassNameMatches(String regex) 正则包名
7. 对象搜索-索引与实例
    1. index是标识在同级的编号
    2. instance是同一个布局文件中的同一类的编号
    3. 相关的API
返回值 API 说明
UiSelector index(int index) 索引
UiSelector instance(int instance) 实例
8. 对象搜索-特殊属性与节点
    1. 特殊属性定位对象相关的API
返回值 API 说明
UiSelector checked(boolean val) 选择属性
UiSelector clickable(boolean val) 可点击属性
UiSelector enabled(boolean val) enabled属性
UiSelector focusable(boolean val) 焦点属性
UiSelector focused(boolean val) 当前焦点属性
UiSelector longClickable(boolean val) 长按属性
UiSelector scrollable(boolean val) 滚动属性
UiSelector selected(boolean val) 背景选择属性
2. 节点属性定位对象相关的API
返回值 API 说明
UiSelector childSelector(UiSelector selector) 从当前类中往下递归找复合条件的子类组件
UiSelector fromParent(UiSelector selector) 从父类中往下递归找复合条件的子类组件
9. 对象搜索-资源ID
    1. 相关的API
返回值 API 说明
UiSelector resourceId(String id) 通过id查找对应的对象,使用时候android>=4.3
  1. UiObject 类

    1. 类介绍
      UiObject 代表手机中各种组件的对象,通过 UiSelector 搜索条件,找到组件对象后,我们要对组件对象进行如点击、长按、拖动、手势等常见的动作模拟操作,UiObject 可以轻松完成这些模拟操作。

    2. 点击与长按

      1. 组件区域位置关系,Rect对象代表一个矩形区域,[Left,Top][Right,Bottom]
      2. 点击与长按相关的api
返回值 API 说明
boolean click() 点击对象
boolean clickAndWaitForNewWindow(long timeout) 点击对象,等待新窗口出现,参数位超时时长
boolean clickAndWaitForNewWindow() 点击对象等待新窗口出现,默认超时时长5500毫秒
boolean clickBottomRight() 点击对象的右下角
boolean clickTopLeft() 点击对象左上角
boolean longClick() 长按对象,对对象执行长按操作
boolean longClickBottomRight() 长按对象右下角
boolean longClickTopLeft() 长按对象左上角
        > 可以通过swipe(startx,starty,endx,endy,steps) 函数传入一个小的位移和较大的步长来实现长按.比如 UiDevice.getInstance.swipe(300,500,310,500,300)

3. 拖拽与滑动对象
    1. 相关的API
返回值 API 说明
boolean dragTo(UiObject destObj,int steps) 拖拽一个对象到另外一个对象上,步长可以设置拖动速度,如果是合并两个图标,步长需要设置长一些(速度变慢)
boolean dragTo(int destX,int destY,int steps) 拖拽一个对象到另外某一个坐标位置,步长可以设置拖动速度
boolean swipeDown(int steps) 拖动对象向下滑动
boolean swipeLeft(int steps) 拖动对象向左滑动
boolean swipeRight(int steps) 拖动对象向右滑动
boolean swipeUp(int steps) 拖动对象向上滑动
4. 输入文本与清除文本

    1. 相关的API
返回值 API 说明
boolean setText(String text) 在对象中输入文本,输入文本的时候首先清除文本,然后输入文本
void clearTextField() 清除编辑框中的文本,长按选中编辑框的所有文本,点击删除
    > 在一些控件中,无法使用长按删除,也就是clearTextField()无法成功,这样如何删除呢?
    > 1. 使用UiDevice.getInstance().pressKey(keyEvent.Key_CODE_MOVE_END);然后使用BACKSPACE键循环删除.
    > 2. 使用UiDevice.getInstance().pressKey(keyEvent.Key_CODE_MOVE_HOME);然后使用delete键循环删除.

5. 获取对象的属性与属性的判断
    1. 获取对象的属性相关的API
返回值 API 说明
Rect getBounds() 获得对象的矩形坐标,句型的左上角和右下角坐标
int getChildCount() 获得下一级子类的数量
String getClassName() 获得对象类名的文本
String getContentDescription() 获得对象的描述属性的文本
String getPackageName() 获得对象的包名文本
String getText() 获得对象的文本属性的文本
Rect getVisibleBounds() 返回课件视图的范围,如果视图的部分是可见的,只有可见的部分报告范围
2. 获取父类与子类节点相关的API
返回值 API 说明
UiObject getChild(UiSelector selector) 获得对象的的子类对象,可以递归获取子孙当中的某一个对象
UiObject getFromParent(UiSelector selector) 从父类获取子类,即按照UiSelector获取兄弟类(递归)
3. 属性的判断相关的API
返回值 API 说明
boolean isCheckable() 检查对象的checkable属性是否为true
boolean isChecked() 检查对象的checked属性是否为true
boolean isClickable() 检查对象的clickable属性是否为true
boolean isEnabled() 检查对象的enabled属性是否为true
boolean isFocusable() 检查对象的focusable属性是否为true
boolean isFocused() 检查对象的focused属性是否为true
boolean isLongClickable() 检查对象的longclickable属性是否为true
boolean isScrollable() 检查对象的scrollable属性是否为true
boolean isSelected() 检查对象的selected属性是否为true
6. 手势的操作
    1. 手势操作: 1.两指操作 2. 三指操作 3. 两指合拢 4. 两指扩张
    2. 手势相关的API
返回值 API 说明
boolean performMultiPointerGesture(PointerCoords[] … touches) 执行单手指触控手势,可以定义任意手势与形状
boolean performTwoPointerGesture(Point startPoint1,Point startPoint2,Point endPoint1,Point endPoint2,int steps) 执行任意两个手指触控手势,模拟两个手指手势
boolean pinchIn(int percent,int steps) 手势操作,两点向内收缩,percent是对角线的百分比
boolean pinchOut(int percent,int steps) 手势操作,两点向外扩张,percent是对角线的百分比
7. 判断对象是否存在
    1. 相关的API
返回值 API 说明
boolean waitForExists(long timeout) 等待对象出现
boolean waitUntilGone(long timeout) 等待对象消失
boolean exists() 检查对象是否存在
  1. UiCollection类
    1. 类介绍
      UiCollection类是UiObject的子类,这个对象代表元素条目的集合,可以用于查找某一容器下的子类集合或者数量,可再加入搜索条件再次从集合中查找指定组件对象.当某个组件定位比较困难的时候,使用UiSelector描述后得到的有可能是多个满足条件的控件集合,因此可以UiCollection,进而再次定位组件.
    2. 使用文本与描述条件从集合中查找对象
      1. 相关的API
返回值 API 说明
UiObject getChildByDescription(UiSelector childPattern,String text) 用描述条件从前面的子集中找到想要的元素
UiObject getChildByText(UiSelector childPattern,String text) 用文本条件从前面的子集中找到想要的元素
UiObject getChildByInstance(UiSelector childPattern,String text) 用实例条件从前面的子集中找到想要的元素
3. 获取某种搜索条件组件的数量
    1. 相关的API
返回值 API 说明
int getChildCount(UiSelector childPattern) 按照UiSelector查找条件获取所有符合条件的组件的数量
UiObject getChildByText(UiSelector childPattern,String text) 用文本条件从前面的子集中找到想要的元素
UiObject getChildByInstance(UiSelector childPattern,String text) 用实例条件从前面的子集中找到想要的元素
  1. UiScrollable类
    1. 类介绍
      UiScrollable是UiCollection的子类,其可以用来生成一个滚动动作的对象,其最大的作用就是可以实现滚动的查找某个元素。比如在“设置”菜单中,“语言和输入法”这个菜单比较靠下,需要滚动后才可以看到(找到),因此就用上了UiScrollable.
    2. 快速滚动
      • 步长,单位距离滑动时间
      • 扫动次数:滑动次数
      • 相关的API
返回值 API 说明
Boolean flingBackward() 按步长为5快速向后滑动
Boolean flingForward() 按步长为5快速向前滑动
Boolean flingToBeginning(int maxSwipes) 自定义扫面次数,按步长为5快速滑动到开始
Boolean flingToEnd() 自定义扫面次数,按步长为5快速滑动到结束
3. 获取列表子元素
    - 相关API
返回值 API 说明
UiObject getChildByDescription(UiSelector childPattern,String text,Boolean allScrollableSearch) 是否允许滚动查找获取具备UiSelector条件元素集合后再以文本描述条件查找对象
UiObject getChildByDescription(UiSelector childPattern,String text) 默认滚动查找获取具备UiSelector条件元素集合后再以文本描述条件查找对象
UiObject getChildByText(UiSelector childPattern,String text,Boolean allScrollableSearch) 是否允许滚动查找获取具备UiSelector条件元素集合后再以文本条件查找对象
UiObject getChildByText(UiSelector childPattern,String text) 默认滚动滚动查找获取具备UiSelector条件元素集合后再以文本条件查找对象
UiObject getChildByInstance(UiSelector childPattern,String text) 用实例条件从前面的子集中找到想要的元素(不滚动)
4. 获取与最大滚动次数常量值
    - 相关的API
返回值 API 说明
int getMaxSearchSwipes() 获取最大滑动次数,默认30
UiScrollable setMaxSearchSwipes(int swipes) 设置最大滑动次数
5. 滑动区域校准常量设置与获取
    - 校准常量指的是,滑动操作坐标是的偏移量,用来取偏移比例
    - 相关的API
返回值 API 说明
double getSwipeDeadZonePercentage() 默认常量值是0.1,10%
UiScrollable setSwipeDeadZonePercentage(double swipeDeadZonePercentage) 设置一个部件的大小在滑动时候视为物接触区域百分比
5. 向前向后滚动
    - 相关的API
返回值 API 说明
Boolean scrollBackward(int steps) 自定义步长快速向后滑动
Boolean scrollBackward() 按步长为5快速向后滑动
Boolean scrollForward(int steps) 自定义步长快速向前滑动
Boolean scrollForward() 按步长为5快速向前滑动
6. 滚动到某个对象
    - 相关的API
返回值 API 说明
Boolean scrollIntoView(UiSelector selector) 滚动到条件元素所在位置,并且尽量让其处于屏幕中央
Boolean scrollIntoView(UiObject obj) 滚动到对象所在位置,并且尽量让其处于屏幕中央
Boolean scrollTextIntoView(String text) 滚动到文本对象所在位置,并且尽量让其处于屏幕中央
Boolean scrollDescriptionIntoView(String text) 滚动到描述所在位置,并且尽量让其处于屏幕中央
Boolean scrollToBeginning(int maxSwipes) 滚动到开始的位置
Boolean scrollToBeginning(int maxSwipes,int steps) 自定义扫描次数与步长滚动到开始的位置
Boolean scrollToEnd(int maxSwipes) 滚动到结束的位置
Boolean scrollToEnd(int maxSwipes,int steps) 自定义扫描次数与步长滚动到结束的位置
7. 设置滚动方向
    - 相关的API
返回值 API 说明
UiScrollable setAsHorizontalList(UiSelector selector) 设置滚动方向是横向滚动
UiScrollable setAsVerticalList(UiObject obj) 设置滚动方向是纵向滚动
  1. UiWatcher类
    1. 类介绍
      • UiWatcher用于处理脚本执行过程中遇到非预想情况的步骤
      • 中断监听检查条件API
返回值 API 说明
boolean checkForCondition() 在测试框架找到一个匹配时,使用UiSelector测试框架将自动调用此处处理方法.在超时未找到匹配项时,框架调用checkForCondition()方法查找设备上的所有已注册的监听检查雕件,返回值是否执行过触发器
2. 监听器操作相关的API,方法或者循环在被打断之后不能回复到循环中,UiDevice是不会触发监听器
返回值 API 说明
void registerWatcher(String name,UiWatcher watcher) 注册一个监听器,当UiSelector无法匹配到对象的时候,触发监听器
void removeWatcher(String name) 取消之前注册的监听器
void resetWatcherTriggers() 重置已经触发过的UiWatcher,重置之后相当于没有运行过
void runWatchers() 强制运行所有的监听器
3. 检查监听器相关的API
返回值 API 说明
boolean hasAnyWatcherTriggered() 检查是否有监听器触发过
boolean hasWatcherTriggered(String watcherName) 检查某个特定的监听器是否触发过
4. 实例代码
1
2
3
4
5
6
7
8
9
10
11
12
UiDevice.getInstance().registerWatcher("phone",new UiWatcher(){
public boolean checkForCondition(){
UiObject call = new UiObject(new UiSelector().text("..."));
// ...
if(call.exists()){
// ...
return true;
}
// ...
return false
}
});
  1. Configurator类,单例

    1. 类介绍

      • Configurator 用于配置脚本各种动作的默认延时,脚本的每个动作之间是有默认延时的,调节这些默认延时可以改变脚本的运行速度,如可实现双击效果,快速输入字符串等操作
    2. Configurator操作相关的API,在修改完默认的延时时间在操作完成之后要恢复.
      |延时项|默认延时|功能描述|API|
      |:-:|:-|:-|:-|
      |动作|3s|设置延时|setActionAckonwledgmentTimeout(long timeout)|
      |动作|3s|获取延时|getActionAckonwledgmentTimeout()|
      |键盘输入|0s|设置延时|setKeyInjectionDelay(long delay)|
      |键盘输入|0s|获取延时|getKeyInjectionDelay|
      |滚动|200ms|设置延时|setScrollAcknowledgmentTimeout(long timeout)|
      |滚动|200ms|获取延时|getScrollAcknowledgmentTimeout()|
      |空闲|10s|设置延时|setWaitForIdleTimeout(long timeout)|
      |空闲|10s|获取延时|getWaitForIdleTimeout()|
      |查找组件|10s|设置延时|setWaitForSelectorTimeout(long timeout)|
      |查找组件|10s|获取延时|getWaitForSelectorTimeout()|

3. 实例代码
    - 更改点击的默认延时,实现快读连续点击或者双击三击
    - 有些情况在输入字符串的时候因为过快无法输入,这个时候可以设置key的延时,使用可以code输入
  1. UiAutomator Report

    1. 错误类型
      • 断言错误: AssertionFailedError
      • 脚本错误: 各种异常
    2. 报告状态
      • 运行状态 : 1=>运行前 -1=>运行完成
      • 结果状态 : 0=>OK -1=>Errors -2=>Failures
      • 运行信息 : 运行前信息 运行中信息 运行后信息
    3. 查看报告:

      • 运行结果分三部分,运行前信息,运行中信息,运行后信息
    4. 输出信息到报告

      • cases 执行顺序
        1. setUP
        2. testCase
        3. tearDown
      • 输出信息使用的API
        • Bundle 类似Map对象
        • getAutomationSupport().sentStatus(int status,Bundle bundle)
          1
          2
          3
          4
          5
          6
          ...
          Bundle bundle = new Bundle();
          bundle.putString("key1","value1");
          bundle.putString("key2","value2");
          getAutomationSupport().sendStatus(99,bundle);
          ...
    5. 通过-e参数,给测试应用传入数据
      adb shell uiautomator runtest xxx.jar –nohup -c com.xxx.xxx#testXXX -e key 12345

1
2
3
4
...
Bundle b = getParams();// 这样可以获取从命令行传郭来的参数
String v = (String) b.get("key");
...