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. kbmmw 5.08 正式发布

    欢迎大家围观. Important notes (changes that may break existing code)         ============================= ...

  2. Document.write和 getElementById(ID)

    在javascript中,document.write()方法:常用来网页向文档中输出内容. 示例:通过document.write()方法,向网页文档中输出了一段文字. document.write ...

  3. RK3288 uboot启动流程

    VS-RK3288嵌入式板卡 U-boot 启动流程小结 bl    board_init_f -> crt0.S    initcall_run_list(init_sequence_f) - ...

  4. 数据库 的几种链接 join

    直接demo,懒的同学可以看看效果 两个表的数据 join和inner join一样 full join报错,可有大神知道原因?

  5. vue学习-自动行合并的table

    测试的效果 测试的html源码截图 v-table在tableGroup.js中定义,以下就render方法,行的所有单元格都在tableGrouper.js中处理 render:function(h ...

  6. 下划线“_”在oracle中不是单纯的表示下划线的意思,而是表示匹配单一任何字符!

    [解决办法]1.使用 escape() 函数escape关键字经常用于使某些特殊字符,如通配符:'%','_'转义为它们原来的字符的意义,被定义的转义字符通常使用'\',但是也可以使用其他的符号.例如 ...

  7. python读取文件时提示"UnicodeDecodeError: 'gbk' codec can't decode

    解决办法1. FILE_OBJECT= open('order.log','r', encoding='UTF-8') 解决办法2. FILE_OBJECT= open('order.log','rb ...

  8. BABOK概述

    BABOK概述 BABOK(Business Analysis Body of Knowlodge: 业务[或商业]分析知识体系)是由位于加拿大的IIBA(International Institut ...

  9. access纯jdbc连接

    Class.forName("com.hxtt.sql.access.AccessDriver"); String url = "jdbc:Access:///c:/a/ ...

  10. R_展示变量之间关系的图形

    #绘制普通矩阵散点图 plot(dataframe) #绘制带有拟合直线,最佳拟合曲线和直方图的矩阵散点图 library(car) attach(dataframe) scatterplotMatr ...