一,uiautomatorviewer是什么?

    Android 4.1发布的,uiautomator是用来做UI测试的。也就是普通的手工测试,点击每个控件元素 看看输出的结果是否符合预期。比如 登陆界面 分别输入正确和错误的用户名密码然后点击登陆按钮看看是否能否登陆以及是否有错误提示等。

功能性或者黑盒UI测试不需要测试人员了解程序如何实现的,只需要验证各种操作的结果是否符合预期即可。这样的测试可以分离团队的开发人员和测试人员。大家各干各的没有太多的交集。

    常用的UI测试方式就是人工验证啦,就是测试人员拿着各种手机分别安装要测试的程序然后看看是否能正确完成各种预定的功能。但是这种验证方式是非常耗时间的,每次回归都要全部验证一边,并且还容易出现人为错误。比较高效和可靠的UI测试方式就是自动化测试。自动化UI测试创建测试代码来执行测试任务,各种测试任务分别覆盖不同的使用场景,然后使用测试框架来运行这些测试任务。而uiautomator 就是你的自动化UI测试工具。

概述

Android SDK在4.1中提供了如下工具来支持UI自动化测试:

  • uiautomatorviewer – 一个图形界面工具来扫描和分析应用的UI控件。
  • uiautomator – 一个测试的Java库,包含了创建UI测试的各种API和执行自动化测试的引擎。

要使用该工具,需要满足如下条件:

  • Android SDK Tools, Revision 21 or higher
  • Android SDK Platform, API 16 or higher

二,uiautomatorviewer的工作流程

  1. 安装要测试的应用到手机中,分析应用的UI界面元素 并确保被测试应用的各个控件可以被测试工具获取到。
  2. 创建知道测试案例来模拟应用中的用户操作步骤。
  3. 编译测试案例代码为Jar包并复制该Jar包到安装了待测应用的测试手机中。
  4. 运行测试并查看结果
  5. 修改任何发现的bug,然后修复并重新测试。

三,分析待测应用的UI元素

在开始编写测试案例代码之前,需要熟悉待测应用的UI元素。可以通过uiautomatorviewer 工具来获取应用的界面截图并分析。uiautomatorviewer 工具提供了一个便利的方式来查看UI布局结构,并且可以查看各个控件的相关属性。利用这些信息可以用来创建UI测试代码。

 分析待测程序的UI组件的步骤: 
       1. 将android设备连接到有开发环境机器上 
       2. 打开命令行终端窗口,进入android sdk tool所在目录 
       3. 运行以下命令: 
             $ uiautomatorviewer 
       4. 捕获到待分析的界面后,点击设备快照“Device Screenshot”按钮 
           注意:如果你连接了多个设备,需要指定ANDROID_SERIAL 环境变量,来说明对哪个设备进行截屏: 
                  a. 运行以下命令,找到你的设备序列号 
                       $ adb devices 
                  b. 设置环境变量ANDROID_SERIAL 
                       在windows上: 
                              set ANDROID_SERIAL=<device serial number> 
                       在unix上: 
                              export ANDROID_SERIAL=<device serial number> 
                如果你只连接一个设备,则不需要设置

    5. 查看应用的UI属性 
              a. 在快照的左侧面板上,可以看到uiautomatorviewer显示的UI组件;在右侧,下边是组件的属性,上边是布局的层次 
              b. 你也可以点击”Toggle NAF Nodes“按钮,来显示uiautomator框架无法访问的UI组件。对于那些组件,只有有限的属性信息可以供uiautomator使用。

测试准备工作

在开始使用uiautomator 之前需要完成如下准备工作:

把待测应用安装到测试手机(设备)上

当你准备测试的时候,待测的应用可能还没有发布到市场上。但是你应该具有该应用的APK安装文件,你可以通过ADB工具来安装待测应用到手机中,或者通过其他工具来安装Apk。

辨别待测应用UI控件

在开始编写uiautomator测试代码之前,需要先辨别待测应用的UI控件元素。一般而言,优秀的待测应用的UI元素应该是可见的并且用户可以操作的。这些UI元素也应该具有可见的文本标签、android:contentDescription值或者二则兼具。

通过uiautomatorviewer 工具可以查看应用的可见控件。具体使用情况见上面所述。

确保待测应用是可访问的

由于uiautomator 工具依赖Android设备的可访问行来获取UI控件,所以这不是非常重要的。要支持uiautomator 工具需要一下条件:

  • 使用android:contentDescription属性给 ImageButton, ImageView, CheckBox和其他控件设置标签。
  • 使用android:hint 属性来标记EditText 控件,而不是使用里面的文本(文本内容用户是可以修改的)。
  • 对于用来提供操作视觉反馈的UI(文本或者图标),都添加一个android:hint 属性来识别。
  • 确保所有用户可操作的界面元素都可以通过方向控制键选中(例如轨迹球)。
  • 通过uiautomatorviewer 工具来确保所有的UI元素都可以被测试工具访问到。还可以通过“辅助功能”(在设置界面)中的“TalkBack”等服务来测试UI的可访问性。
设置开发环境

如果你使用的是Eclipse(Adt),则Android SDK提供了额外的工具来帮助你编写uiautomator测试代码和打包测试项目。在Eclipse中创建uiautomator测试项目的过程如下:

  1. 创建新的Java项目(注意不是Android项目)。在该项目中来创建测试代码。
  2. 在Project Explorer视图中,右键点击测试项目,选择“ Properties > Java Build Path”,然后选择“Libraries” tab界面。在“Libraries”界面选择“ Add Library > JUnit”来添加JUnit3 库。然后点击“Add External JARs… ”并导航到Android SDK目录。选择platforms目录下面的 uiautomator.jar 和 android.jar文件。
  3. 设置好的build path如下图:

uiautomator项目类路径设置

如果你不使用Eclipse,则需要确保/platforms/目录中的uiautomator.jar 和 android.jar 位于项目Build path中。

配置好开发环境后就可以开始编写测试代码了。

创建uiautomator 测试案例

uiautomator 测试案例(Test case)需要继承至UiAutomatorTestCase 类。而UiAutomatorTestCase 类继承至junit.framework.TestCase类,所以可以用JUnit的Assert类来比较测试结果。

UI测试的首要任务就是访问测试手机。一般都是从手机的主屏开始测试的。通过uiautomator 提供的API可以从主屏来模拟用户的操作。下面会介绍具体示例。

uiautomator API

uiautomator API在 uiautomator.jar 文件中。这些API分别如下:

UiDevice

代表设备状态。在测试中,可以通过UiDevice实例来检测设备的各种属性,例如当前的屏幕方向以及屏幕尺寸。同时还可以通过UiDevice实例来执行设备级别的操作,例如 把设备设置为横屏或者竖屏、按下Home按键等。

如下是模拟按下Home按键的代码: 
getUiDevice().pressHome();

UiSelector

代表一个搜索UI控件的条件。如果发现多个满足条件的控件则会返回第一个控件。返回的结果为UiObject对象。在构造UiSelector的时候可以组合使用多个属性来定位具体的控件。如果没有找到控件则会抛出 UiAutomatorObjectNotFoundException 异常。还可以使用childSelector()函数来嵌套UiSelector 对象。例如,下面的代码演示了如何在当前界面中查找第一个ListView中的带有文本属性为Apps的子控件。

UiObject appItem = new UiObject(new UiSelector()
.className("android.widget.ListView").instance(1)
.childSelector(new UiSelector().text("Apps")));
UiObject

代表一个UI控件。通过UiSelector来查找UiObject。 
如下示例代码演示了如何查找当前显示界面中的取消按钮和确认按钮:

UiObject cancelButton = new UiObject(new UiSelector().text("Cancel"));
UiObject okButton = new UiObject(new UiSelector().text("OK"));

查找到的UiObject实例可以在其他测试代码中重用。需要注意的是:每次使用UiObject做操作的时候uiautomator 都会在当前屏幕重新查找该控件。

如下代码uiautomator 工具在当前界面查找文本内容为“OK”的控件。如果存在并且可用则模拟用户点击该控件。

if(okButton.exists() && okButton.isEnabled())
{
okButton.click();
}

还可以限制仅仅查找特定类型的控件。例如 如下代码只查找文本为“Cancel”和“OK”的android.widget.Button类型控件。

UiObject cancelButton = new UiObject(new UiSelector().text("Cancel")
.className("android.widget.Button"));
UiObject okButton = new UiObject(new UiSelector().text("OK")
.className("android.widget.Button"));
UiCollection

代表控件的集合。获取UiCollection的方式和UiObject一样,通过 UiSelector查找。 UiCollection对应Android系统中的ViewGroup以及子控件。 
如下代码演示如何通过UiSelector来获取包含视频集合的UiCollection。

UiCollection videos = new UiCollection(new UiSelector()
.className("android.widget.FrameLayout"));

如果每个视频是放到LinearLayout中的,则可以通过如下方式获取视频的数目:

int count = videos.getChildCount(new UiSelector()
.className("android.widget.LinearLayout"));

如果需要查找标签为“Cute Baby Laughing”的视频,并点击。则可以通过如下方式:

UiObject video = videos.getChildByText(new UiSelector()
.className("android.widget.LinearLayout"), "Cute Baby Laughing");
video.click();

同样还可以模拟其他用户操作。例如,模拟选择视频的操作如下:

UiObject checkBox = video.getChild(new UiSelector()
.className("android.widget.Checkbox"));
if(!checkBox.isSelected()) checkbox.click();
UiScrollable

代表可滚动的控件。可以用UiScrollable来模拟水平或者垂直滚动的UI元素。如果需要操作的元素在屏幕外需要滚动屏幕才能看到的情况下需要使用UiScrollable。

例如,下面的代码显示了如何模拟滚动到“Settings ”菜单并点击“About tablet”菜单的操作。

UiScrollable settingsItem = new UiScrollable(new UiSelector()
.className("android.widget.ListView"));
UiObject about = settingsItem.getChildByText(new UiSelector()
.className("android.widget.LinearLayout"), "About tablet");
about.click()

其他API参考uiautomator api文档。

一个简单的uiautomator 测试案例

如下是一个简单的测试案例代码,模拟了点击Home键回到主屏,然后点击所以应用按钮打开所有应用列表,并滚动到时钟应用。打开时钟应用 并选择闹铃界面的第一个闹钟设置,修改该设置的开关。然后返回到时钟界面再进入倒计时界面。

package com.uia.example.my;

import android.widget.ListView;
import android.widget.Switch; import com.android.uiautomator.core.UiObject;
import com.android.uiautomator.core.UiObjectNotFoundException;
import com.android.uiautomator.core.UiScrollable;
import com.android.uiautomator.core.UiSelector;
import com.android.uiautomator.testrunner.UiAutomatorTestCase; public class LaunchSettings extends UiAutomatorTestCase { // TODO 重要注意: 在运行该测试代码的时候 需要先把手机语言环境设置为英文。
public void testDemo() throws UiObjectNotFoundException { // 模拟 HOME 键点击事件
getUiDevice().pressHome(); // 现在打开了主屏应用,模拟点击所有应用按钮操作来启动所有应用界面。
// 如果你使用了uiautomatorviewer来查看主屏,则可以发现“所有应用”按钮的
// content-description 属性为“Apps”。可以使用该属性来找到该按钮。
UiObject allAppsButton = new UiObject(new UiSelector().description("Apps")); // 模拟点击所有应用按钮,并等待所有应用界面起来
allAppsButton.clickAndWaitForNewWindow(); // 在所有应用界面,时钟应用位于Apps tab界面中。下面模拟用户点击Apps tab操作。
// 找到 Apps tab 按钮
UiObject appsTab = new UiObject(new UiSelector().text("Apps")); // 模拟点击 Apps tab.
appsTab.click(); // 然后在 Apps tab界面,模拟用户滑动到时钟应用的操作。
// 由于Apps界面是可以滚动的,所有用
// UiScrollable 对象.
UiScrollable appViews = new UiScrollable(new UiSelector().scrollable(true)); // 设置滚动模式为水平滚动(默认为垂直滚动)
appViews.setAsHorizontalList(); if (allAppsButton.exists() && allAppsButton.isEnabled()) {
// allAppsButton在当前界面已经不可见了 所以这里不会执行
allAppsButton.click();
}
// 查找时钟应用并点击
UiObject settingsApp = appViews.getChildByText(
new UiSelector().className(android.widget.TextView.class.getName()), "Clock");
settingsApp.clickAndWaitForNewWindow(); // 验证当前显示 的应用包名为时钟 UiObject settingsValidation = new UiObject(new UiSelector().packageName("com.google.android.deskclock"));
// 如果不存在则出错提示
assertTrue("Unable to detect Clock", settingsValidation.exists()); // 模拟点击时间tab
UiObject clock = new UiObject(new UiSelector().description("Clock"));
clock.clickAndWaitForNewWindow();
// 模拟点击下方的闹钟图标
UiObject alarms = new UiObject(new UiSelector().description("Alarms"));
alarms.clickAndWaitForNewWindow(); UiScrollable list = new UiScrollable(new UiSelector().className(ListView.class.getName()));
if (list.getChildCount() > 0) {
UiObject listIndex0 = list.getChild(new UiSelector().index(0));
UiObject switchBtn = listIndex0.getChild(new UiSelector().className(Switch.class.getName())); boolean isChecked = switchBtn.isChecked(); switchBtn.click();
}
// 模拟点击返回键
getUiDevice().pressBack(); UiObject timer = new UiObject(new UiSelector().description("Timer"));
timer.clickAndWaitForNewWindow(); }
}
打包测试代码并在测试机上运行

如下步骤打包测试代码并在测试机运行的步骤:

1.创建打包测试代码的Build脚本。通过如下命令来生成Build脚本:

<android-sdk>/tools/android create uitest-project -n <name> -t 1 -p <path>
<name>是包含测试代码的项目名称,<path>是包含测试代码的项目文件路径。-t后面的1是Android sdk版本id。

注意: 在创建Build脚本之前,已经创建好了测试项目并编写好了测试代码。只不过该测试项目还没有包含打包脚本所以无法打包运行。在创建Build脚本的时候,<name>属性就是测试项目的名称、<path>就是已经创建的测试项目在电脑中的文件夹路径。 如果电脑上安装了多个版本的Android sdk,则需要运行/tools/android list target 来查看每个SDK的id。选择4.1以上的id即可。

2. 设置ANDROID_HOME 环境变量。

Windows:set ANDROID_HOME=

Unix:export ANDROID_HOME=

3. 打开命令行创建,导航到第一步中的目录中,运行 ant build 来打包。

4. 通过adb push命令把上一步打包出来的jar文件复制到测试手机中。

adb push <path>/bin/<name>.jar /data/local/tmp/

类似如下代码:

adb push ~/dev/workspace/LaunchSettings/bin/LaunchSettings.jar /data/local/tmp/

运行uiautomator 测试
下面是运行 LaunchSettings.jar jar包中测试代码的命令。测试代码位于com.uia.example.my包中。

adb shell uiautomator runtest LaunchSettings.jar -c com.uia.example.my.LaunchSettings

关于uiautomator 的更多信息参考这里:http://developer.android.com/tools/help/uiautomator/index.html

最佳实践

下面是一些使用uiautomator 做UI测试的最佳实践

  • 在待测应用可能运行的尽可能多的设备上跑uiautomator 测试。例如 在不同的屏幕密度、不同的屏幕尺寸上运行测试。
  • 还应该在一些常规场景下测试UI,例如 电话打入情况、网络连接断开的情况等。

uiautomatorviewer详解的更多相关文章

  1. Uiautomator ——API详解(转载http://www.cnblogs.com/by-dream/p/4921701.html)

    转载来源: 简单的例子 以一个简单的例子开始吧.我们完成一个 " 打开QQ,进入QQ空间,然后退出 " 的case. 代码如下: package QQ; import java.i ...

  2. 【Android测试】【第十二节】Uiautomator——API详解

    ◆版权声明:本文出自carter_dream的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/4921701.html 简单的例子 以一个 ...

  3. (转)Uiautomator——API详解

    原文链接:http://www.cnblogs.com/by-dream/p/4921701.html#3328376 以一个简单的例子开始吧.我们完成一个 " 打开QQ,进入QQ空间,然后 ...

  4. Uiautomator ——API详解

    版权声明:本文出自carter_dream的博客,转载必须注明出处. 转载请注明出处:http://www.cnblogs.com/by-dream/p/4921701.html 简单的例子 以一个简 ...

  5. Linq之旅:Linq入门详解(Linq to Objects)

    示例代码下载:Linq之旅:Linq入门详解(Linq to Objects) 本博文详细介绍 .NET 3.5 中引入的重要功能:Language Integrated Query(LINQ,语言集 ...

  6. 架构设计:远程调用服务架构设计及zookeeper技术详解(下篇)

    一.下篇开头的废话 终于开写下篇了,这也是我写远程调用框架的第三篇文章,前两篇都被博客园作为[编辑推荐]的文章,很兴奋哦,嘿嘿~~~~,本人是个很臭美的人,一定得要截图为证: 今天是2014年的第一天 ...

  7. EntityFramework Core 1.1 Add、Attach、Update、Remove方法如何高效使用详解

    前言 我比较喜欢安静,大概和我喜欢研究和琢磨技术原因相关吧,刚好到了元旦节,这几天可以好好学习下EF Core,同时在项目当中用到EF Core,借此机会给予比较深入的理解,这里我们只讲解和EF 6. ...

  8. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  9. Android Notification 详解(一)——基本操作

    Android Notification 详解(一)--基本操作 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 源码:AndroidDemo/Notification 文中如有纰 ...

随机推荐

  1. zoj2853 Evolution

    给定一个进化的矩阵图,问在m次之后最终的物种有多少个,实际上这和线性代数及其应用里的一个例题是一样的...总之就相当于煞笔的套个矩阵不断去乘m次,然后每次都会根据得到进化后各物种的个数,矩阵快速幂求一 ...

  2. cogs——1364. 聚会

    1364. 聚会 ★   输入文件:partyb.in   输出文件:partyb.out   简单对比时间限制:1 s   内存限制:128 MB [问题描述] 小S想要从某地出发去同学k的家中参加 ...

  3. 洛谷——P1036 选数

    题目描述 已知 n 个整数 x1,x2,…,xn,以及一个整数 k(k<n).从 n 个整数中任选 k 个整数相加,可分别得到一系列的和.例如当 n=4,k=3,4 个整数分别为 3,7,12, ...

  4. Java DynamoDB 增加、删除、修改、查询

    准备jar包 <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sd ...

  5. 使用maven时,如何修改JVM的配置参数;maven命令执行时到底消耗多少内存?

    maven是使用java启动的,因此依赖JVM,那么如何修改JVM参数? MAVEN_OPTS 在系统的环境变量中,设置MAVEN_OPTS,用以存放JVM的参数,具体设置的步骤,参数示例如下: MA ...

  6. 踩坑录-IDEA编辑器:找不到TomcatService或ApplicationServers----TomcatService使用指南

    一.找不到TomcatService或ApplicationServers Setp1. 检查IDEA版本 检查IDEA版本是否为Ultimate(终极版需要激活),Community(社区版免费无需 ...

  7. 【cocos2d-x 3.7 飞机大战】 决战南海I (三) 敌机实现

    如今来实现敌机类 敌机和我方飞机相似,具有生命值.能够发射子弹.而且有自己的运动轨迹.事实上能够为它们设计一个共同的基类,这样能够更方便扩展. 不同的敌机,应设置不同的标识.属性 // 敌机生命值 c ...

  8. session 生命周期

    以前看到书上session 的生命周期,知道session的生命周期是在第一次访(即打开浏览器输入地址成功访问)的时候被创建.同时HttpSessionListener接口的sessionCreate ...

  9. ios25---图片拉伸

    控制器: // // ViewController.m // 12-图片的拉伸问题 // // Created by xiaomage on 15/12/30. // Copyright © 2015 ...

  10. What does jQuery.fn mean?

    n jQuery, the fn property is just an alias to the prototype property. The jQuery identifier (or $) i ...