它是一个Android自动化测试框架,是谷歌在Android4.1版本发布时推出的一款用Java编写的UI测试框架。它只能用于UI也就是黑盒方面的测试。所以UiAutomator只能运行在4.1以后的版本中。其最大的特点就是可以跨进程操作,我们可以使用uiautomator框架提供的一些方便的API来对安卓应用进行一系列的自动化测试操作,如点击、滑动、键盘输入、长按以及常用的断言方法等。可以替代以前繁琐的手工测试。
下面总结一下该框架的几个优点:
- Google自家推出的,其稳定性和后续的维护更新可以得到保障,运行时也有更多的权限。
- 可以跨进程操作,这点比起其它基于instrumentation框架的自动化工具如Robotium是无法直接做到的。
- 运行速度快。 缺点:
- 不支持Android4.1以下的版本。
- 不支持Webview,所以一般无法对浏览器应用进行测试。
UiAutomator 框架原理分析:
首先,UiAutomator是Google参考微软的UiAutomation提供的一套用在Android上的自动化测试框架。基于Android AccessilibilityService提供。那么至于什么是AccessilibilityService,在这里简单介绍下:Android AccessilibilityService,是一个可访问服务,它是一个为增强用户界面并帮助残疾用户的应用程序,或者用户可能无法完全与设备的交互。举个简单的例子,假如一个用户在开车。那么用户就有可能需要添加额外的或者替代的用户反馈方式。其应用方式一般有两种:
第一种方法是:UiAutomatorView + monkey。它与hierachyview + monkey差不多。其区别是:UiAutomatorView通过ADB向设备侧发送一个dump命令,而不是建立一个socket,下载一个包含当前界面控件布局信息的xml文件。相比较hierachyview下载的内容而言,该文件小很多。因此,从效率上讲,这种方法比第一种应用模式快很多。
第二种方法是: 直接调用UiAutomator框架对外提供的API,主要有UiDevice、UiSelector、UiObject和 UiScrollable等。其原理与第一种方式即HierachyView + Monkey差不多。其过程大致是:首先,UiAutomator测试框架通过Accessibilityservice,获取当前窗口的控件层次关系及属性信息,并查找到目标控件。若是点击事件,则计算出该控件的中心点坐标。其次,UiAutomator通过 InputManager.getInstance().injectInputEvent隐藏接口来注入用户事件(点击、输入类操作),从而实现跨进程自动化的目的。
UiAutomatorTestCase :这个类是继承自Junit TestCase (Junit),对外提供setup、teardown等,以便初始化用例、清除环境等。所以我们在编写的UiAutomator 的脚本时一般都要继承这个类,这样就可以直接使用它的一些方法和Junit单元测试框架中的Assert断言机制。
UIAutomator2.0
We’re pleased to announce the release of UIAutomator 2.0! This version is a significant update from the previous release. Most importantly, UI Automator is now based on Android Instrumentation and you can build and run tests with the ‘./gradlew connectedCheck’ command.
UiAutomator2.0的jar包并不是在以前SDK/platforms/android-19/下。现在我们要这么做
通过Android SDK Manager中的 Android Support Repository 项进行安装
下载下来的jar包的路径为/extras/android/m2repository
新建一个android项目,编写一个简单的应用
在build.gradle中配置依赖项:
1
2
3
4
5
6
7
8
9dependencies {
androidTestCompile 'com.android.support.test:runner:0.3'
// Set this dependency to use JUnit 4 rules
androidTestCompile 'com.android.support.test:rules:0.3'
// Set this dependency to build and run Espresso tests
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2'
// Set this dependency to build and run UI Automator tests
androidTestCompile 'com.android.support.test.uiautomator:uiautomator-v18:2.1.1'
}设置AndroidJunitRunner为默认的testInstrumentationRunner
1
2
3
4
5android {
defaultConfig {
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
}编写测试代码,在androidTest目录下面新建测试类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38public class LoginTest extends InstrumentationTestCase {
protected UiDevice device = null;
protected String appName = "magicCard";
public void runApp(String appName) throws UiObjectNotFoundException, RemoteException {
device = UiDevice.getInstance(getInstrumentation());
device.pressHome();
device.waitForWindowUpdate("", 2000);
UiObject2 allAppsButton = device.findObject(By.desc("Apps"));
allAppsButton.click();
device.waitForWindowUpdate("", 2000);
UiScrollable appViews = new UiScrollable(new UiSelector().scrollable(true));
appViews.setAsHorizontalList();
UiObject settingsApp = appViews.getChildByText(new UiSelector().className(TextView.class.getName()), appName);
settingsApp.clickAndWaitForNewWindow();
assertTrue("Unable to detect app", settingsApp != null);
}
@Override
public void setUp() throws RemoteException, UiObjectNotFoundException {
this.runApp(appName);
}
@Override
public void tearDown() throws RemoteException, UiObjectNotFoundException {
//Empty for the moment
}
public void testUS1() {
UiObject2 usernameLabel = device.findObject(By.clazz(TextView.class.getName()).text("Username"));
assertTrue("Username label not found", usernameLabel != null);
}
}
基于Instrument的方便一点就是不需要remote debug的方式进行调试。并且做参数化之类的也方便了很多。 2.0不用再继承UiAutomatorTestCase,但却需要继承InstrumentationTestCase。
获取设备的方式也变化了,UiDevice.getInstance(getInstrumentation()) 这才是正确的使用方法。之前常用的两种方式都不再可行。
可以通过如下的adb命令调用
1 | adb shell am instrument -w -r -e debug false -e class com.cxq.uiautomatordemo.UiTest com.cxq.uiautomatordemo.test/android.test.InstrumentationTestRunner |
在dependencies中用到了compile、testCompile、androidTestCompile三种依赖方式,让我们来看看他们有什么区别:
compile:参与编译,并且会打包到debug/release apk中。 testCompile:只参与单元测试编译,不会打包到debug/release apk包中,不需要设备支持。 androidTestCompile:只参与UI测试编译,不会打包到debug/release apk包中,需要设备支持。
除此之外还有Provided、APK、Debug compile和Release compile:
Provided:只参与编译,不会打包到debug/release apk中。 APK:不参与编译,只会打包到debug/release apk中。 Debug compile:只参与debug编译,只会打包到debug apk中。 Release compile:只参与release编译,只会打包到release apk中。
UIAutomator1.0
新建Java工程
导入lib包 android.jar 和 uiautomator.jar ,选中点击右键Add to buildPath
新建测试类demo
1
public class Demo extends UiAutomatorTestCase{}
写测试方法A,B,C(testcase)
编译运行:
<android-sdk>/tools/android create uitest-project -n <name> -t 1 -p <path>
说明一下各个参数的作用,如果已经将android sdk的路径配置到了系统的path中,输入命令“android create uitest-project”就可以查看到相应的帮助
-n --name : Project name.
就是在eclipse中创建的项目的名字。-t --target : Target ID of the new project. [required]
这个id是本机上android targets的id,可以通过命令 “android list”来查询,得到结果,选择android-17以上版本前面所对应的id,运行完成后,工作空间下生成文件build.xml
5.2. 修改build.xml 将help改为build
1 | <?xml version="1.0" encoding="UTF-8"?> |
5.3.在build.xml上点击右键,选择“Run As” -> “Ant Build”,编译成功,在工作空间bin下生成一个jar包demo.jar
5.4. adb push demo.jar /data/local/tmp/
5.5. adb shell uiautomator runtest demo.jar -c A -c B -c C
(可指定多个testcase,不指定则运行所有)
uiautomator的help帮助: 支持三个子命令:rutest/dump/events
- runtest命令-c指定要测试的class文件,用逗号分开,没有指定的话默认执行测试脚本jar包的所有测试类.注意用户可以以格式$class/$method来指定只是测试该class的某一个指定的方法
- runtest命令-e参数可以指定是否开启debug模式
- runtest命令-e参数可以指定test runner,不指定就使用系统默认。我自己从来没有指定过
- runtest命令-e参数还可以通过键值对来指定传递给测试类的参数
UiAutomator2改进
基于 Instrumentation,可以获取应用Context,使用 Android服务及接口
基于 Junit4,测试用例无需继承于任何父类,方法名不限,使用注解 Annotation进行
UI执行效率比 1.0 快,测试执行可使用AndroidJunit 方式及gradle 方式
API 更新,新增UiObject2、Until、By、BySelector等:APIFor UI Automator
Log 输出变更,以往使用System.out.print输出流回显至执行端,2.0 输出至Logcat
AndroidJUnitRunner AndroidJUnitRunner InstrumentationTestRunner Fundamentals of Testing UI Automator androidx.test Test UI for multiple apps Instrumentation