UiAutomator2.0升级填坑记
UiAutomator2.0升级填坑记
SkySeraph May. 28th 2017
Email:skyseraph00@163.com
更多精彩请直接访问SkySeraph个人站点:www.skyseraph.com
啰嗦
Google Android Developers 在2015年3月就发布了UiAutomator 2.0版本(下文简称U2),而公司的核心产品中用到还是UiAutomator老版本(下文简称U1),业界用U2的也不是很多,虽然有诸多问题和不便(如高版本OS中不支持Remote Debug等),但大家似乎在苟延残喘中麻木了。 公司以前也有专家做过研究和探索,毕竟老项目是万级别的,涉及诸多算法和复杂业务逻辑,遇到几个问题最终不了了之。于是乎,又到了我手里了。
重大特性
1. 基于 Instrumentation,使用Instrumentation test runner即可运行UiAutomator,反之,也即在基于Instrumentation的test中也能使用UiAutomator; 可以获取应用Context,可以使用Android服务及接口。
2. 基于 Junit4,测试用例无需继承于任何父类,方法名不限,使用Annotation进行; U1需要继承UiAutomatorTestCase,测试方法需要以test开头.
3. 与U1的Maven或Ant构建方式不同,U2采用Gradle进行构建; U2输出为APK,Android工程,而U1为Java工程,输出jar包。
  4. 新增UiObject2、Until、By、BySelector等接口, 详细请参考官方文档。
其中,U2必须明确EditText框才能向里面输入文字,U1直接指定父类也可以在子类中输入文字。
5. Log日志输出变更。U1可以使用System.out.print输出流回显至执行端,而U2输出到Logcat。
6. 命令运行差异。
adb shell uiautomator runtest xx.jar -c package.name.ClassName
adb shell am instrument -w -r -e class com.xx.xx com.xx.xx.test/ android.support.test.runner.AndroidJUnitRunner
代码中运行:
Runtime.getRuntime().exec(“*“)
device.executeShellCommand(“*“)
  命令格式:instrument [options] component,详细命令格式介绍参考官方文档。
基础使用
新建Android Studio工程。
gradle中添加依赖。
androidTestCompile(‘com.android.support.test.espresso:espresso-core:2.2.2’{
exclude group: ‘com.android.support’, module: ‘support-annotations’
})
androidTestCompile ‘com.android.support.test:runner:0.5’
androidTestCompile ‘com.android.support.test:rules:0.5’
androidTestCompile ‘com.android.support.test.uiautomator:uiautomator-v18:2.1.2’
androidTestCompile ‘com.android.support:support-annotations:25.3.1’
如需要依赖jar包
androidTestCompile fileTree(dir: 'libs', include: ['*.jar'])
- androidTest目录下添加测试用例。
 
@RunWith(AndroidJUnit4.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class XXTest {
public Bundle bundle;
public UiDevice device;
private Instrumentation instrumentation; @BeforeClass
public static void beforeClass() { } @Before
public void before() {
// Initialize UiDevice instance
instrumentation = InstrumentationRegistry.getInstrumentation();
device = UiDevice.getInstance(instrumentation);
bundle = InstrumentationRegistry.getArguments();
assertThat(device, notNullValue());
} @After
public void after() {
L.i(TAG + "After");
} @AfterClass
public static void afterClass() {
L.i(TAG + "AfterClass");
} public Bundle getParams() {
return bundle;
}
}
采坑记
编译错误.
这个应该说是官方故意坑爹吧,U2的包名结构发生了变化,所以需要将之前所有用到的U1相关API包名进行替换,具体为com.android.uiautomator.core. -> android.support.test.uiautomator.
反射相关.
这个有点坑爹,还是U2包名结构问题(原项目很多地方用到了反射获取U1相关类/方法等),除非对原业务非常熟悉,否则只有遇到问题分析时才会发现此坑,读者以后如果遇到这种类似包结构变化的问题,先不管三七二十一,全局搜索相关字段全局了解再说。当然,如果用到了混淆,也要对应修改。UiAutomatorTestCase相关.
问题:去除所有测试类中的extend UiAutomatorTestCase后异常。因为原项目依赖于UiAutomatorTestCase中的getPara API来获取U1命令传参。
方案:修改成U2的InstrumentationRegistry.getArguments方式。日志相关.
问题:原项目中业务逻辑依赖System.out.println日志输出结果,而U2中System.out.println不会回显到终端显示,直接影响之前业务逻辑的执行。
方案:使用Instrumentation.sentStatus自定义状态。属性文件.
描述:这个有点意思,原项目为Java工程,有很多属性配置在properties属性文件中,大概有20来个properties文件。而对属性文件的读取是在一个common的公共jar包中,采取的是Thread.currentThread().getContextClassLoader().getResourceAsStream方式。
问题:①属性配置文件无法打包进apk中 ②读取方式问题
解决:
方法1: 将属性配置文件全部放入assets目录,然后通过Context().getAssets().open方式读取;而原先的jar中的公共类,抽离出来作为业务类。
方法2: 通过gradle自定义打包,将所有属性配置文件打包进apk中,建议。xml配置文件.
问题:原工程用到了RPC框架,有xml配置文件,存在与上述properties类似问题。
解决:gradle自定义打包。权限问题.
问题:Android M+对权限进行了升级,本工程需要用到文件存储权限,仅在Manifest中声明WRITE_EXTERNAL_STORAGE权限还不够。
解决:
方法1:
@Before
public void grantPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
getInstrumentation().getUiAutomation().executeShellCommand("pm grant "+getTargetContext().getPackageName()+"android.permission.WRITE_EXTERNAL_STORAGE");
}
}
方法2:通过Rule
@Rule
public final PermissionsRule permissionsRule = new PermissionsRule(
new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE});
- NoClassDefFoundError问题.
 
问题:在Android 4.4手机出现NoClassDefFoundError问题,Instrumentation消息为
INSTRUMENTATION_RESULT: longMsg=java.lang.NoClassDefFoundError: org.junit.runner.manipulation.Filter$1
解决: MultiDex手动拆包A
①gradle文件中添加multiDexKeepProguard
defaultConfig {
    multiDexEnabled true
    multiDexKeepProguard file('multidex.pro')
}
②multidex文件中添加
-keep class android.support.multidex.** {*;}
-keep public class org.junit.runner.** {*;}
- 系统签名问题.
描述:此问题是后续测试中才发现的,原来的稳定性/兼容性测试上的性能指标参数大部分显示为空,极其诡异,后面花了很大功夫进行分析发现,很多指标会出现会出现类似Permission Denial : cannot dump 错误,获取不到任何数据。因为原工程需要获取电池、CPU、内存等等几十项性能参数指标,有很大一部分是通过sh读取系统文件等方式获取的,通过Runtime.getRuntime().exec 或者 ProcessBuilder.start方式, 比如通过dump中的dump battery获取电池信息,因为dumpsys涉及android:protectionLevel=”signatureOrSystem”,需要 权限,需要声明android:sharedUserId=”android.uid.system”,需要系统签名. …
解决:
①系统签名(无奈之举).
②采用device.executeShellCommand,注意只支持API 21+. 
REFS
后记
本文首发于skyseraph.com:“UiAutomator2.0升级填坑记”
同步发表/转载 cnBlogs/ …
By SkySeraph-2017
UiAutomator2.0升级填坑记的更多相关文章
- Android项目开发填坑记-Fragment的onBackPressed
		
Github版 CSDN版 知识背景 Fragment在当前的Android开发中,有两种引用方式,一个是 Android 3.0 时加入的,一个是supportV4包中的.这里简称为Fragment ...
 - Android项目开发填坑记-Fragment的onAttach
		
背景 现在Android开发多使用一个Activity管理多个Fragment进行开发,不免需要两者相互传递数据,一般是给Fragment添加回调接口,让Activity继承并实现. 回调接口一般都写 ...
 - minikube windows hyperx填坑记
		
minikube windows hyperx填坑记 安装了一天半,还是没行,先放弃 开始 minikube start --vm-driver=hyperv --hyperv-virtual-swi ...
 - 浅谈html5 video 移动端填坑记
		
这篇文章主要介绍了浅谈html5 video 移动端填坑记,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 本文介绍了html5 video 移动端填坑记,分享给大家,具体 ...
 - Appium+python自动化(十三)- 输入中文 - 一次填坑记(超详解)
		
简介 无论你在哪里,在做什么都会遇到很多坑,这些坑有些事别人挖的,有些是自己挖的.别人挖的叫坑人,自己挖的叫自杀,儿子挖的叫坑爹.因此在做app自动化道路上也不会是一帆风顺的,你会踩很多坑,这些坑和你 ...
 - Android项目开发填坑记-so文件引发的攻坚战
		
故事的最初 我负责的项目A要求有播放在线视频的功能,当时从别人的聊天记录的一瞥中发现百度有相关的SDK,当时找到的是Baidu-T5Player-SDK-Android-1.4s,项目中Demo的so ...
 - Java web 开发填坑记 2 -如何正确的创建一个Java Web 项目
		
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72566261 本文出自[赵彦军的博客] Java web 开发填坑记 1-如何正确 ...
 - Cloudera Manager 5.9 和 CDH 5.9 离线安装指南及个人采坑填坑记
		
公司的CDH早就装好了,一直想自己装一个玩玩,最近组了台电脑,笔记本就淘汰下来了,加上之前的,一共3台,就在X宝上买了CPU和内存升级了下笔记本,就自己组了个集群. 话说,好想去捡垃圾,捡台8核16线 ...
 - Elasticsearch 填坑记
		
前言 技术的发展日新月异,传统企业数据库Oracle.SqlServer.DB2,Mysql等在今日不断的被各种大厂自研数据库取代,当然也有类似Elasticsearch等优秀的满足海量数据所使用的开 ...
 
随机推荐
- 马踏棋盘算法递归+回溯法实现 C语言
			
r为矩阵的行,c为矩阵的列 将结果输出到当前目录下的results.txt. 结果将给出:1.是否存在路径使马可以按要求走遍所有的方格: 2.解的总数: 3.程序执行的时间: #include< ...
 - encodeURI与decodeURI
			
Global对象的ecodeURI方法可以对URI进行编码,与其类似的还有一个方法encodeURIComponent方法. 相应的对URI的解码方法也有两个:decodeURI.decodeURIC ...
 - SSIM(结构相似度算法)不同实现版本的差异
			
前言 最近用ssim测试图片画质损伤时,发现matlab自带ssim与之前一直使用的ssim计算得分有差异,故和同事开始确定差异所在. 不同的SSIM版本 这里提到不同的ssim版本主要基于matla ...
 - document.querySelectorAll() 与document.getElementTagName() 的区别
			
这个区别我估计大神都不知道,问题源于博主,细节被一个妹子发现的 事情经过是这样 <ul> <li>item</li> <li></li> & ...
 - javascript 玩转Date对象
			
前言:最近在做一个日期选择功能,在日期转换的时候经常换到晕,总结一下常用的Date对象的相关用法,方便日后直接查看使用- 1. new Date()的使用方法有: 不接收任何参数:返回当前时间: 接收 ...
 - xhr.readyState就绪状态
			
0:初始化,XMLHttpRequest对象还没有完成初始化 1:载入,XMLHttpRequest对象开始发送请求 2:载入完成,XMLHttpRequest对象的请求发送完成 3:解析,XMLHt ...
 - Linux 下搭建www服务器
			
偶然的机会接触了前端开发,尽管最初的意愿是后台. 不过现在看来,前端后台数据库密不可分! 回想起来感觉自己学习的层次也还很好,因为之前有学习c语言.c++的基础,所以在学习html,js的过程中感觉还 ...
 - gtest 操作指南
			
首先,下载gtest-17.0,CSDN上就可以免费下载. 然后,打开gtest-17.0下的msvc文件夹,运行gtest.sln,右键解决方案,选择生成解决方案,此时会在gtest-17.0/ms ...
 - 如何快速轻松学习bootstrap
			
我以前也是通过看一些视频教程来学的,比如慕课网上的,比如51cto上的那些零基础入门bootstrap什么的,还有一些培训班里流传出来的,感觉晕乎乎的,不知所云. 还是在后面不断使用的过程中慢慢体会到 ...
 - java基础,流程控制语句
			
流程控制语句 条件语句: if语句: *if(条件 boolean类型) ...