UI Automator 相关介绍:

  • 跨应用的用户界面自动化测试
  • 包含在 AndroidX Test(https://developer.android.com/training/testing) 中
  • 支持的 Android 系统:>= Android 4.3 (API level 18)
  • 基于 instrumentation,依赖于 AndroidJUnitRunner 测试运行器

设置 UI Automator(Set up UI Automator)

在编写测试代码前,先确保以下两个配置:

1、测试代码存放位置

2、项目依赖(https://developer.android.com/training/testing/set-up-project)

(1) 添加 Gradle 依赖(Add Gradle dependencies)

  • app 目录下的 build.gradle 添加:
allprojects {
repositories {
jcenter()
google()
}
}
  • dependencies 添加需要的 AndroidX Test Package, 比如:
dependencies {
...
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
}
android {
... // Gradle automatically adds 'android.test.runner' as a dependency.
useLibrary 'android.test.runner' useLibrary 'android.test.base'
useLibrary 'android.test.mock'
}

(2) 添加 manifest 声明(Add manifest declarations)

此步骤可选,具体请看 https://developer.android.com/training/testing/set-up-project#add-manifest-declarations

当前面的配置完成后,进行其他配置:

app下的build.gralde:

dependencies {
...
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
}

当所有配置都完成后,进行被测应用的 UI 组件分析,确保能被识别以及接入控制。

检查设备上的用户界面(Inspect the UI on a device)

uiautomatorviewer:

(1) 启动手机上的被测应用

(2) 手机连接电脑

(3) 打开 Terminal, 进入目录 <android-sdk>/tools/

(4) 运行:uiautomatorviewer

查看应用的用户界面属性:

(1) 点击左上角 "Device Screenshot" 按钮

(2) 左边是 UI 组件,右下半部分是属性,右上半部分是布局层级

(3) 可选功能:点击右上角 "Toggle NAF Nodes" 按钮(黄色三角形,内有感叹号),查看无法被识别/访问的UI组件。---这个功能我都没搞懂怎么用,点击后貌似没效果

确保 activity 可访问(Ensure your activity is accessible)

Android 原生元素具有更好的访问性,利于测试代码的编写,无需额外的支持

如果是自定义 UI 元素,需要(1)创建一个继承自 ExploreByTouchHelper 的实体类(2)通过调用 setAccessibilityDelegate() 将新创建的类的实例和特定的自定义 UI 元素相关联

给自定义视图元素添加无障碍功能的其他参考资料:https://developer.android.com/guide/topics/ui/accessibility/custom-views.html

学习资料 for 提高 Android 的无障碍性/可访问性:https://developer.android.com/guide/topics/ui/accessibility/apps.html

创建一个 UI Automator 测试类(Create a UI Automator test class)

UI Automator 测试类的写法和 JUnit 4 测试类的写法是一样的。

JUnit 4 测试类的学习资料:https://developer.android.com/training/testing/unit-testing/instrumented-unit-tests.html#build

在测试类开头添加注解:@RunWith(AndroidJUnit4.class)

同时,明确 AndroidX Test 中的 AndroidJUnitRunner 类为默认的测试运行器。这个步骤的详细描述:https://developer.android.com/training/testing/ui-testing/uiautomator-testing.html#run

在 UI Automator 测试类中执行以下编程模型:

  1. 获取一个 UiDevice 对象去接入测试设备,调用 getInstance() 方法,传入 Instrumentation 对象作为参数。
  2. 通过 UiObject 对象调用 findObject() 方法接入显示在设备上的 UI 组件(例如,当前手机屏幕显示的用户界面)。
  3. 通过调用 UiObject 方法在 UI 组件上模拟一个交互的动作。例如,调用 performMultiPointerGesture() 方法模拟多指触控,调用 setText() 方法编辑文本框。当测试包含多个 UI 组件或者更加复杂的操作序列时,在第二步和第三步中可重复调用各种 API.
  4. 当执行完这些用户交互的动作后,检查返回的结果是否符合预期。

    这些步骤在以下章节会讲的更加详细。

访问用户界面组件 (Access UI components)

UiDevice: 接入和控制设备状态的首要方法,可执行设备级别的行为,例如改变屏幕旋转方向、按下硬件按钮、以及点击 home 和 menu 键。

从设备的主屏幕开始测试是一个好的实践。在主屏幕(或者其他你在设备上选定的开始位置),可以调用 UI Automator API 提供的方法和指定的 UI 元素进行交互。

以下代码片段展示了如何获取一个 UiDevice 的实例以及模拟按下 home 键的操作:

import org.junit.Before;
import androidx.test.runner.AndroidJUnit4;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Until;
...
@RunWith(AndroidJUnit4.class)
@SdkSuppress(minSdkVersion = 18)
public class ChangeTextBehaviorTest { private static final String BASIC_SAMPLE_PACKAGE
= "com.example.android.testing.uiautomator.BasicSample";
private static final int LAUNCH_TIMEOUT = 5000;
private static final String STRING_TO_BE_TYPED = "UiAutomator";
private UiDevice device; @Before
public void startMainActivityFromHomeScreen() {
// Initialize UiDevice instance
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); // Start from the home screen
device.pressHome(); // Wait for launcher
final String launcherPackage = device.getLauncherPackageName();
assertThat(launcherPackage, notNullValue());
device.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)),
LAUNCH_TIMEOUT); // Launch the app
Context context = ApplicationProvider.getApplicationContext();
final Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(BASIC_SAMPLE_PACKAGE);
// Clear out any previous instances
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intent); // Wait for the app to appear
device.wait(Until.hasObject(By.pkg(BASIC_SAMPLE_PACKAGE).depth(0)),
LAUNCH_TIMEOUT);
}
}

示例代码中的声明:@SdkSuppress(minSdkVersion = 18), 帮助确定测试只运行在 Android4.3(API level 18)或更高级别的设备上。(UI Automator 框架要求的)

  • findObject()
  • UiObject
UiObject cancelButton = device.findObject(new UiSelector()
.text("Cancel")
.className("android.widget.Button"));
UiObject okButton = device.findObject(new UiSelector()
.text("OK")
.className("android.widget.Button")); // Simulate a user-click on the OK button, if found.
if(okButton.exists() && okButton.isEnabled()) {
okButton.click();
}

指定一个选择器(Specify a selector)

UiSelector 类:在当前显示的用户界面中查询一个特定的元素。

  • childSelector()
  • UiAutomatorObjectNotFoundException
UiObject appItem = device.findObject(new UiSelector()
.className("android.widget.ListView")
.instance(0)
.childSelector(new UiSelector()
.text("Apps")));

tips:

  • 如果在一个页面上找到一个以上的相同元素,自动返回第一个匹配的元素作为目标 UiObject.
  • 可以通过整合多个属性来缩小搜索范围。
  • 如果没有找到目标元素,抛出 UiAutomatorObjectNotFoundException 异常。
  • 可以使用 childSelector() 方法缩小多个 UiSelector 实例范围。
  • 如果有 Resource ID, 用这个代替 text 和 content-descripter.
  • text 元素比较脆弱,有多种原因可能导致测试失败。(比如:多语言)

    在选择区域中去明确一个对象状态是非常有用的。比如:选择一个已选中的列表以进行取消选中状态,调用 checked() 方法,将参数设为 "true".

执行动作(Perform actions)

当获取 UiObject 对象后,可以调用 UiObject 类中的方法在其上执行相应操作:

  • click(): 点击
  • dragTo(): 拖动
  • setText(): 设置文本
  • clearTextField(): 清空文本
  • swipeUp(): 向上滑动
  • swipeDown(): 向下滑动
  • swipeLeft(): 向左滑动
  • swipeRight(): 向右滑动

通过 getContext() 方法获取到 Context 后,可以进行发送 Intent 或者启动 Activity 的操作。

public void setUp() {
... // Launch a simple calculator app
Context context = getInstrumentation().getContext();
Intent intent = context.getPackageManager()
.getLaunchIntentForPackage(CALC_PACKAGE);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Clear out any previous instances
context.startActivity(intent);
device.wait(Until.hasObject(By.pkg(CALC_PACKAGE).depth(0)), TIMEOUT);
}

在集合上执行动作(Perform actions on collections)

  • UiCollection 类:在一个 item 的集合上模拟用户操作(例如,歌曲列表或者邮件列表)。

    如何创建一个 UiCollection 对象:明确一个搜索UI容器或者其他子 UI 元素集合的 UiSelector. 例如,包含子 UI 元素的 layout 视图。
UiCollection videos = new UiCollection(new UiSelector()
.className("android.widget.FrameLayout")); // Retrieve the number of videos in this collection:
int count = videos.getChildCount(new UiSelector()
.className("android.widget.LinearLayout")); // Find a specific video and simulate a user-click on it
UiObject video = videos.getChildByText(new UiSelector()
.className("android.widget.LinearLayout"), "Cute Baby Laughing");
video.click(); // Simulate selecting a checkbox that is associated with the video
UiObject checkBox = video.getChild(new UiSelector()
.className("android.widget.Checkbox"));
if(!checkBox.isSelected()) checkbox.click();

在可滚动视图中执行动作(Perform actions on scrollable views)

  • UiScrollable 类:在手机屏幕上模拟垂直或者水平的滚动操作。这个类适用于当需要找到屏幕外的 UI 元素时,可以通过滚动操作将这个 UI 元素带到屏幕内。
UiScrollable settingsItem = new UiScrollable(new UiSelector()
.className("android.widget.ListView"));
UiObject about = settingsItem.getChildByText(new UiSelector()
.className("android.widget.LinearLayout"), "About tablet");
about.click();

验证结果(Verify results)

InstrumentationTestCase 继承自 TestCase,可以使用标准的 JUnit Assert 方法进行结果验证。

以下代码片段展示了如何验证计算器加法:

private static final String CALC_PACKAGE = "com.myexample.calc";
public void testTwoPlusThreeEqualsFive() {
// Enter an equation: 2 + 3 = ?
device.findObject(new UiSelector()
.packageName(CALC_PACKAGE).resourceId("two")).click();
device.findObject(new UiSelector()
.packageName(CALC_PACKAGE).resourceId("plus")).click();
device.findObject(new UiSelector()
.packageName(CALC_PACKAGE).resourceId("three")).click();
device.findObject(new UiSelector()
.packageName(CALC_PACKAGE).resourceId("equals")).click();
// Verify the result = 5
UiObject result = device.findObject(By.res(CALC_PACKAGE, "result"));
assertEquals("5", result.getText());
}

在设备或虚拟机上运行 UI Automator 测试用例(Run UI Automator tests on a device or emulator)

可以通过 Android Studio 或者命令行运行 UI Automator tests. 确保项目的默认 instrumentation runner 是 AndroidJUnitRunner.

参考资料(Additional resources)

Samples:

https://github.com/googlesamples/android-testing/tree/master/ui/uiautomator/BasicSample 基础的UI Automator 示例代码

Codelabs:

https://codelabs.developers.google.com/codelabs/android-testing/index.html


欢迎关注微信公众号"测试开发Stack"

自动化测试 | UI Automator 进阶指南的更多相关文章

  1. 自动化测试 | UI Automator 入门指南

    自动化测试的定义,这里先引用一段维基百科的定义: 在软件测试中,测试自动化(英语:Test automation)是一种测试方法,使用特定的软件,去控制测试流程,并比较实际的结果与预期结果之间的差异. ...

  2. iOS进阶指南试读之UI篇

    iOS进阶指南试读之UI篇 UI篇 UI是一个iOS开发工程师的基本功.怎么说?UI本质上就是你调用苹果提供给你的API来完成设计师的设计.所以,想提升UI的功力也很简单,没事就看看UIKit里的各个 ...

  3. 【读书笔记】读《高性能网站建设指南》及《高性能网站建设进阶指南:Web开发者性能优化最佳实践》

    这两本书就一块儿搞了,大多数已经理解,简单做个标记.主要对自己不太了解的地方,做一些记录.   一.读<高性能网站建设指南> 0> 黄金性能法则:只有10%~20%的最终用户响应时间 ...

  4. Weex入门与进阶指南

    Weex入门与进阶指南 标签: WeexiOSNative 2016-07-08 18:22 59586人阅读 评论(8) 收藏 举报 本文章已收录于:  iOS知识库  分类: iOS(87)  职 ...

  5. UI Automator 介绍

    简介 Android 4.3发布的时候包含了一种新的测试工具–uiautomator,uiautomator是用来做UI测试的.也就是普通的手工测试,点击每个控件元素 看看输出的结果是否符合预期.比如 ...

  6. Appium自动化(10) - appium高级元素定位方式之 UI Automator API 的详解

    如果你还想从头学起Appium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1693896.html 前言 前面介绍过根据id,clas ...

  7. UI Automator Viewer获取手机镜像时报错

    使用UI Automator Viewer获取手机镜像时报错,具体信息如下: Error while obtaining UI hierarchy XML file: com.android.ddml ...

  8. HTML5游戏开发进阶指南(亚马逊5星畅销书,教你用HTML5和JavaScript构建游戏!)

    HTML5游戏开发进阶指南(亚马逊星畅销书,教你用HTML5和JavaScript构建游戏!) [印]香卡(Shankar,A.R.)著 谢光磊译 ISBN 978-7-121-21226-0 201 ...

  9. HTML5游戏开发进阶指南

    <HTML5游戏开发进阶指南> 基本信息 作者: (印)香卡(Shankar,A.R.)    译者: 谢光磊 出版社:电子工业出版社 ISBN:9787121212260 上架时间:20 ...

随机推荐

  1. C#中get和set属性的作用

    c#在定义类时,通常要把类中声明的对象封装起来,使得外界不能访问这个属性.上述代码中如果去掉set部分,则外界只能读取name的值,如果去掉get部分,则只能给name赋值.这样就可以控制外界对私有属 ...

  2. vi/vim 三种模式的操作

    来源:http://www.runoob.com/linux/linux-vim.html ps:刚刚进入vi/vim 是命令模式 一.命令模式 i 切换到输入模式,以输入字符. x 删除当前光标所在 ...

  3. spring深入学习(四)-----spring aop

    AOP概述 aop其实就是面向切面编程,举个例子,比如项目中有n个方法是对外提供http服务的,那么如果我需要对这些http服务进行响应时间的监控,按照传统的方式就是每个方法中添加相应的逻辑,但是这些 ...

  4. 1004 Counting Leaves 对于树的存储方式的回顾

    一种新的不使用左右子树递归进行树高计算的方法,使用层次遍历 树的存储方式: 1.本题提供的一种思路: 使用(邻接表的思想)二维数组(vector[n])表示树,横坐标表示 父节点,每一行表示孩子. 能 ...

  5. 解决jenkins shell执行sonar-scanner提示命令存在的问题

    通过jenkins的以下三个方式去执行sonar-scanner,抛如下错误. Send files or execute commands over SSH before the build sta ...

  6. Unity3D编辑器扩展(四)——扩展自己的组件

    前面已经写了三篇: Unity3D编辑器扩展(一)——定义自己的菜单按钮 Unity3D编辑器扩展(二)——定义自己的窗口 Unity3D编辑器扩展(三)——使用GUI绘制窗口 今天写第四篇,扩展自己 ...

  7. Python数据结构之单链表

    Python数据结构之单链表 单链表有后继结点,无前继结点. 以下实现: 创建单链表 打印单链表 获取单链表的长度 判断单链表是否为空 在单链表后插入数据 获取单链表指定位置的数据 获取单链表指定元素 ...

  8. 《Linux就该这么学》

    参加了第19期课程的培训,感谢刘老师的辛苦付出,课程讲的很好,真心推荐老刘的这本书真是<Linux就该这么学>!!! 本书是由全国多名红帽架构师(RHCA)基于最新Linux系统共同编写的 ...

  9. 入门SQL操作

    结构化查询语言:SQL:Structured Query Language 分类: 针对的操作对象不同.分成不同的语言: 1.数据操作(管理)语言( DML) 查询:获得数据.(DQL) 管理:增加. ...

  10. 11-Python操作excel

    1.python操作excel需要用到的库 python操作excel主要用到xlrd和xlwt这两个库,即xlrd是读excel,xlwt是写excel的库.可以直接pip安装这两个库,pip in ...