UiAutomator是一个非常好的黑盒主动化测试框架,可以在不知道目标应用内部具体实现的情况下进行测试,并且它的最重要优点是能够跨进程。而Espresso属于白盒测试框架,需要在有代码的情况下进行测试,并且它不支持跨进程,现在由于使用AndroidJUnitRuner替代了Instrumentaion,将UiAutomator并入AndroidJUnitRuner
从而将二者的优点合并在一起显得更加强大。

我们之前以及介绍了Espresso自动化测试框架,它是一个白盒测试框架,需要在有代码的情况下进行测试,接下来要介绍的UiAutomator2也是一个用于测试功能的框架,和Espresso不同的是UiAutomator是一个黑盒自动化测试框架,可以在不知道代码的情况下进行测试,
它可以跨进程进行测试,但是UiAutomator2 有一些不足比如在无法测试Toast弹出。对Intent测试也不如Espresso强大。Espresso的强大的地方是语法简介,测试运行快,能够测试Toast,以及Intent,使用IdingSource还可以测试异步操作。能不能将二者结合起来进行测试呢?答案是肯定的。
在Android Studio 环境下需要添加UiAutomator只需要添加如下依赖。或者下载离线jar包。

androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.0.0'

UiAutomator2与Espresso的测试思路是一样的,都是查找对象,执行操作,检查操作结果。UiAutomator2主要由UiDevice,UiObject,UiSelector,UiScrollable,UiCollection,UiWatcher这些元素组成。UiAutomator2更是在原先UiAutomation基础上添加了更多的类,我们在稍后的部分将会对其进行展开介绍。

Uidevice

提供关于设备的状态信息。也可以使用这个类来模拟装置上的用户的行为。

  • 初始化UiDevice

    private UiDevice(Instrumentation instrumentation)
    public static UiDevice getInstance(Instrumentation instrumentation)
  • 获取某个对象

    public UiObject findObject(UiSelector selector)
    public boolean hasObject(BySelector selector)
    public UiObject2 findObject(BySelector selector)
    public List<UiObject2> findObjects(BySelector selector)
  • 与屏幕相关

    public void wakeUp() throws RemoteException 唤起界面
    public void sleep() throws RemoteException 休眠设备
    public boolean isScreenOn() throws RemoteException 判断界面是否处于亮屏状态
    public Point getDisplaySizeDp()
    public int getDisplayWidth()获取显示器的宽度,以像素为单位。
    public int getDisplayHeight()获取显示器的高度,以像素为单位。
    public boolean isNaturalOrientation() 判断是否处于原始状态
    public int getDisplayRotation()获取当前界面的旋转状态
    public void freezeRotation() throws RemoteException 禁用传感器和设备的旋转且在当前的旋转屏幕状态冻结
    public void unfreezeRotation() throws RemoteException重新启用传感器和允许物理旋
    public void setOrientationLeft() throws RemoteException 左转屏幕
    public void setOrientationRight() throws RemoteException 右转屏幕
    public void setOrientationNatural() throws RemoteException 将屏幕状态设置为原始位置
    public String getProductName()获取当前产品名
  • 与设备操作相关

    public boolean pressMenu()短按MENU键
    public boolean pressBack()短按返回键.
    public boolean pressHome()短按HOME键.
    public boolean pressSearch()短按搜索键
    public boolean pressDPadCenter()轨迹球
    public boolean pressDPadDown()轨迹球
    public boolean pressDPadUp()轨迹球
    public boolean pressDPadLeft()轨迹球
    public boolean pressDPadRight()轨迹球
    public boolean pressDelete()短按删除键
    public boolean pressEnter()短按回车键.
    public boolean pressKeyCode(int keyCode) 短按键盘代码
    public boolean pressRecentApps() throws RemoteException 短按弹出RecentApp按钮
    public boolean openNotification() 弹出通知栏
    public boolean openQuickSettings() 弹出快速设置
    public boolean click(int x, int y) 在任意坐标指定的坐标执行一个点击
    public boolean swipe(int startX, int startY, int endX, int endY, int steps)
    public boolean drag(int startX, int startY, int endX, int endY, int steps)
    public boolean takeScreenshot(File storePath)
  • 其他

    public boolean waitForWindowUpdate(final String packageName, long timeout) 等待窗口内容更新事件的发生
    public void waitForIdle() 等待当前的应用程序处于空闲状态
    public void waitForIdle(long timeout) 等待当前的应用程序处于空闲状态
    public String getCurrentPackageName() 返回当前界面的包名的字符串
    public String getLauncherPackageName()
  • 执行命令

    public String executeShellCommand(String cmd) throws IOException
  • UiWatcher相关

监听器用于在测试过程中处理可能打断测试的突发事件,当脚本其他未知情况打断执行的时候,如果有监听器则会跳转到监听器中执行,我们可以使用监听器做一些特殊的处理如,来电,闹钟日常等测试。比如我们在测试某个用例这时候突然来了个电话突然进入通话界面,这时候就会导致测试失败,但是如果使用了UIWatcher,就可以跳到UiWatcher进行处理,
。这部分将会在UiWatcher中展开介绍。

public void registerWatcher(String name, UiWatcher watcher) 注册一个监听器,用户处理某个步骤被打断的情况的异常,
public void removeWatcher(String name) 移除之前注册的指定监听器
public void runWatchers() 强制运行所有的监听器
public void resetWatcherTriggers() 重置一个监听器
public boolean hasWatcherTriggered(String watcherName) 检查某个特定的监听器是否触发过
public boolean hasAnyWatcherTriggered()检查是否有监听器触发过
private void setWatcherTriggered(String watcherName)
public <R> R performActionAndWait(Runnable action, EventCondition<R> condition, long timeout)
UiSelector && BySelector && By
UiSelector

UiSelector用于获取操作对象,这个和Espresso withid,withText一样用于匹配某个对象,UiSelector 获取对象一般依具备两类,一类是控件属性,一类是控件层级关系。

  • 在UiAutoMator中用于获取对象的属性有如下几种:
    index
    instance
    class
    package
    Content-desc
    checkable
    checked
    clickable
    enabled
    focusable
    focused
    Scrollable
    Long-clickable
    Password
    Selected
    Bounds
    上述这些属性最容易混淆的是index和instance
    index 为同一级别组件的编号(也就是同一个父类的下的子类的序号不一定是同类)
    instance 针对的是整个页面的同一类控件的序号

这些属性可以通过uiautomationViewer来获取。关于如何获取就不再这里展开介绍了。

  • 使用文本来匹配控件
  • 使用描述来匹配控件
  • 使用类名来匹配控件
  • 使用包名来匹配控件
  • 使用资源ID来匹配控件
  • 使用其他属性来匹配控件
  • 使用index和instance来匹配控件
  • 我们每个页面View的层级关系中有如下几种关系:
    父节点
    子节点
    同胞节点
    先辈节点
    后辈节点
  • 使用index和instance来匹配控件
BySelector && By

BySelector 和 By是在UiAutomator2引入的是UiSelector的简化,但是BySelector的意义不大,一般个人角度我用得比较多的是By方式,十分简洁。
对应的匹配方法也和UiSelector有了一点改变,但是改变不是很多如果熟悉UiSelector可以不用任何学习的情况下切换过来。

clazz 设置类名称的条件匹配
desc 通过正则匹配设置一个描述搜索条件
descContains 通过包含匹配设置一个描述的搜索条件
descStartsWith 通过起始匹配设置一个描述的搜索条件
descEndsWith 通过结尾匹配设置一个描述的搜索条件
pkg通过包名正则匹配设置一个搜索条件
res 通过资源ID正则匹配设置一个搜索条件
text 通过文本正则匹配设置一个搜索条件
textContains 通过文本包含匹配设置一个搜索条件
textStartsWith 通过文本起始匹配设置一个搜索条件
textEndsWith 通过文本结尾匹配设置一个搜索条件
checkable
checked
clickable
enabled
focusable
focused
longClickable
scrollable
使用深度搜索来定位控件

我们知道View的层级结构是有一定层次的,我们在搜索的时候莪可以借助这个层次关系进行定位。

depth(int exactDepth) 设置搜索条件匹配元素,通过固定的层级深度
depth(int min, int max) 设置搜索条件匹配元素,通过一定范围的层级深度
maxDepth(int max) 设置一个搜索条件匹配元素,但是不能超过指定的深度
minDepth(int min) 设置一个搜索条件匹配元素,但是从指定深度开始向下搜索
hasChild(BySelector childSelector) 搜索子类
hasDescendant(BySelector descendantSelector) 搜索后代
hasDescendant(BySelector descendantSelector, int maxDepth) 搜索后代
UiObject && UiObject2

UiObject
代表一个组件对象,一般是通过UiSelector定位到的,在定位到的UiObject上可以执行一系列操作,UiObject2实在UiAutomator2中引入的接口方面差别不是很大。

  • 点击长按等操作
  • 拖拽/滑动操作
  • 文本操作
  • 获取属性/属性判断

  • 获取层级关系
  • 手势操作
  • 判断对象时候存在
UiCollection

UiCollection 代表元素集合
它首先按照一定的条件枚举出容器类界面所有符合条件的子元素,再在从符合条件的元素再次通过一定的条件最终定位需要的组件
UiCollection的接口比较少常见的Api如下:

public UiObject getChildByDescription(UiSelector childPattern, String text)
public UiObject getChildByInstance(UiSelector childPattern, int instance)
public UiObject getChildByText(UiSelector childPattern, String text)
public int getChildCount(UiSelector childPattern)
UiScrollable

UiScrollable专门处理滚动事件,提供各种滚动方法, 这个和Espresso的onData情形差不多都是用于测试不能完全显示的元素的控件。UiScrollable继承自UiCollection下面是对应的继承关系。

  • UiScrollable支持的操作
  • 快速滑动
  • 选择子项
  • 设置滑动参数
  • 向前向后滑动

  • 设置滑动方向
UiWatcher

在测试框架无法找到一个匹配时,使用Uiselector测试框架将自动调用此处理程序方法。在超时未找到匹配项时,框架调用checkforCondition()方法查找设备上的所有已注册的监听检查条件。我们可以使用此方法来处理中断问题保证测试用例正常运行。
监听器要在中断代码之前运行。
但是我个人而言还没实际在项目的测试用例中使用,主要原因是我们只能罗列优先的可能性,但是并不是所有的可能情况都列举出来,第二由于我们在测试的时候都是在理想状态下,所以一般都没写这部分逻辑,但是最好还是将这部分考虑在内。

UiDevice.getInstance().registerWatcher("answerThePhone",new UiWatcher() { 
UiObject ReceiveObject = new UiObject(new UiSelector().text("下拉接听"));
@Override
public boolean checkForCondition() {
// TODO Auto-generated method stub
System.out.println("监听器检查函数开始运行-挂电话");
if (jietingObject.exists()) {
System.out.println("监听器条件判断成功--挂电话");
int y = UiDevice.getInstance().getDisplayHeight();
int x = UiDevice.getInstance().getDisplayWidth();
UiDevice.getInstance().swipe(x / 2, y / 2, x / 2,10, 10);
return true;
}
System.out.println("监听器条件判断失败--挂电话");
return false;
}});
Until

我们在执行自动化测试的时候常常有一种需求就是需要等待某个属性达到某个条件的时候执行某个操作。要实现这个目的就必须借助于新引入的UiObject2的wait方法,

public <R> R wait(UiObject2Condition<R> condition, long timeout)

它会等待等到当前Object满足某个条件的时候返回一个boolean值用于表示条件是否满足。这里的UiObject2Condition就是借助Until来获取的,Until有很多静态方法可以很容易创建检测的条件。
下面是常见的检测条件:

public static UiObject2Condition<Boolean> checkable(final boolean isCheckable)
public static UiObject2Condition<Boolean> checked(final boolean isChecked)
public static UiObject2Condition<Boolean> clickable(final boolean isClickable)
public static UiObject2Condition<Boolean> enabled(final boolean isEnabled)
public static UiObject2Condition<Boolean> focusable(final boolean isFocusable)
public static UiObject2Condition<Boolean> focused(final boolean isFocused)
public static UiObject2Condition<Boolean> longClickable(final boolean isLongClickable)
public static UiObject2Condition<Boolean> scrollable(final boolean isScrollable)
public static UiObject2Condition<Boolean> selected(final boolean isSelected)
public static UiObject2Condition<Boolean> descMatches(final Pattern regex)
public static UiObject2Condition<Boolean> descMatches(String regex)
public static UiObject2Condition<Boolean> descEquals(String contentDescription)
public static UiObject2Condition<Boolean> descContains(String substring)
public static UiObject2Condition<Boolean> descStartsWith(String substring)
public static UiObject2Condition<Boolean> descEndsWith(String substring)
public static UiObject2Condition<Boolean> textMatches(final Pattern regex)
public static UiObject2Condition<Boolean> textMatches(String regex)
public static UiObject2Condition<Boolean> textNotEquals(final String text)
public static UiObject2Condition<Boolean> textEquals(String text)
public static UiObject2Condition<Boolean> textContains(String substring)
public static UiObject2Condition<Boolean> textStartsWith(String substring)
public static UiObject2Condition<Boolean> textEndsWith(String substring)
public static EventCondition<Boolean> newWindow()
public static EventCondition<Boolean> scrollFinished(final Direction direction)
public static SearchCondition<Boolean> gone(final BySelector selector) 某个Object消失
public static SearchCondition<Boolean> hasObject(final BySelector selector)
public static SearchCondition<UiObject2> findObject(final BySelector selector)
public static SearchCondition<List<UiObject2>> findObjects(final BySelector selector)

Configulator

主要用于配置一些参数

public Configurator setWaitForIdleTimeout(long timeout) 
public long getWaitForIdleTimeout()
public Configurator setWaitForSelectorTimeout(long timeout)
public long getWaitForSelectorTimeout()
public Configurator setScrollAcknowledgmentTimeout(long timeout)
public long getScrollAcknowledgmentTimeout()
public Configurator setActionAcknowledgmentTimeout(long timeout)
public long getActionAcknowledgmentTimeout()
public Configurator setKeyInjectionDelay(long delay)
public long getKeyInjectionDelay()

http://blog.csdn.net/swordgirl2011/article/category/3242309

Contents
  1. 1. Uidevice
  2. 2. UiSelector && BySelector && By
    1. 2.1. UiSelector
    2. 2.2. BySelector && By
  3. 3. 使用深度搜索来定位控件
  4. 4. UiObject && UiObject2
  5. 5. UiCollection
  6. 6. UiScrollable
  7. 7. UiWatcher
  8. 8. Until
  9. 9. Configulator