史上最简单Robotium跨进程操作实践——基于ADB框架

2023-11-09

楼主原创,分享不易,转载请注明出处,谢谢。


2015年2月3日更新:

有些朋友在用真机尝试本方法时,抛出了InputStream cannot be null的异常。该异常是由于adb运行在robotium框架中时,是完全运行在手机中的,此时它的权限受到android系统的限制。而原框架是用在PC端的,这才导致了该异常的出现。具体的原因分析可以见我的这篇文章:http://blog.csdn.net/qingchunjun/article/details/43343735。

该问题的修改可以参考这里:http://blog.csdn.net/qingchunjun/article/details/43448371

注意:大家如果使用真机的话,务必使用已经root过的手机,否则将由于系统目录权限限制的原因导致文件生不成。


Robotium是Android平台下一款非常优秀的自动化测试框架,它做android平台自动化的优势想必看到这篇文章的人应该都很清楚。但优点归优点,缺点也比较多,最明显的缺点有两个,一是必须要和被测系统签名保持一致,二是不能做任何跨进程的操作。

 

很多小伙伴知道怎么用robotium,也知道它有这些限制,但不知道其中的原因。这里简单地说一下,robotium的这些先天不足的主要原因是由于它本身是基于instrumentation机制的,这既有好处也有坏处。好处是通过instrumentation注入到被测进程,从而与被测进程运行在同一进程空间,使得它能够非常方便地识别被测应用中的被测对象,并对这些对象进行操作。坏处是既然robotium已经跟被测应用”合体”了,那么根据android的进程隔离机制,它自然也被系统隔离在其他进程之外,无法跨进程操作任何对象,如图(1)所示。

 

图(1)Android进程沙箱示意图

 

其实使用相同的签名对于单应用的测试来说并不是难事,网上有很多应用重签名的方法和工具供大家使用。但不能跨进程操作确实成为了robotium最大的软肋,很多第三方的应用测试或多或少都有一些跨进程操作的测试场景,所以不少人因为这个问题而放弃了robotium,甚是可惜啊。

 

作为robotium的铁杆粉之一(我最开始接触android自动化测试就是用的robotium),断断续续用了好几年,一直觉得是android平台最好用的自动化测试工具之一。对于robotium怎样突破进程的限制也做过一些研究,网上比较多的解决方案无外乎有以下几种:

1. 自己写服务做server,基于AIDL或编写socket与monkeyserver进行通讯,然后在robotium测试脚本里调用接口方法来间接地进行跨进程的操作,这种方式可以参考下这篇文章的例子:http://www.robotium.cn/archives/584。文章的作者只是给出了思路,我自己曾经按照这种方法去实现过,发现该方法的优势是比较稳定,缺点就是实现起来确实比较复杂,而且有些操作无法找到现成的系统aidl接口来进行操作,比如调用拍照操作,所以其实例子并不是很多,技术上的局限性较大。

2. 基于广播和service服务。这种方法的实现方式可以参考http://www.ltesting.net/ceshi/open/kygncsgj/2013/0507/206229.html这篇文章的描述。这种方法我没有亲自去试过,但不难发现这种方法原理稍微简单些,但该方法貌似需要系统签名,而且自己写广播和服务来调用系统api,难度也不算小,所以一般不建议使用这种方式。

 

综合上面的这些跨进程的解决方案,其实都感觉不太理想,对于很多初学者来说不是太难实现就是局限性比较大,一直没有找到一个比较理想的解决方案。直到后来在testerhome上看到一个技术很牛的兄弟把常用的adb命令做了一个很完备的封装(PS:真的是很全了,至少常用的adb命令都在,我甚至之前都没有想过adb命令还能做这么多事情),做成了一个独立的测试辅助工具。我就突然联想到为何不能使用adb命令来辅助robotium进行跨进程操作呢?既然该框架已经封装了基于adb的所有操作,而且adb又是不受系统限制的,那么基于这个框架理论上进行跨进程操作是没有任何问题的。后来经过试验,确实效果不错,轻量级、操作简单、使用方便,并且轻松跨进程,真是居家测试、屌丝逆袭的必备神器啊。好了,闲话不多说了,接下来我们就来详细地看看究竟是怎么用的。

 

先来简单地介绍下这个adb命令框架的常用接口。这个框架里有三个主要的包,分别介绍如下:

 

xuxu.autotest这个包里面主要有两个类,一个是AdbDevice,封装了功能测试中常用的一些操作,如获取当前activity的名称和包名、获取设备分辨率、关闭应用、点击对象等常用功能,非常实用。另一个类是XuImage,顾名思义,即封装了一些常见的图片操作,如得到指定边界的图片截图、对比图片是否一致、截取图片等。

 

xuxu.autotest.element这个包主要用于获取被测对象,主要是封装了一个Position对象,用于通过Class Name、Id、Contentdesc等属性来获取一个被测对象,其底层是通过uiautomator来dump 当前ui的xml文件的,可以获取到所有对象节点的xml文件。

 

xuxu.autotest.utils这个包里面主要提供了对Date日期时间的操作,ImageUtil对图片的操作及正则表达式和shell语句的操作的封装,方便大家的使用。总的来说整个框架的接口设计还是非常齐全的,可以实现很多常用功能,具体功能大家可以自己看源码和帮助文档来摸索。

 

接下来就进入我们本次的主题——跨进程。为了方便大家理解,我会在本文中选择两个非常常见的跨进程操作场景来说明如何跨进程,也就是大家喜闻乐见的相机拍照打电话来进行演示。

 

例子1、跨进程操作之相机拍照。

被测程序非常简单,程序界面截图如下图(2)所示:


图(2)

 

点击第一个界面的“拍照片”按钮后,进入界面2,点击其中的“拍张照片”后启动系统的相机,当用户按下拍照功能键后,系统可以将用户拍下的照片显示在应用中,以备后续浏览或者是上传。由于相机应用和我们所写的被测应用是两个不同的应用,所以这就属于典型的跨进程操作,Robotium框架本身是无法对这个相机界面进行操作的。

 

接下来看看关键的测试工程怎么创建的。测试工程的创建方法非常简单,操作步骤如下:

1. 首先按照常规的android测试工程的建法,创建一个常规测试工程。

2. 在工程中引入robotium和adbForAndroid的jar包。

这样,我们的测试工程就准备好了。

接下来的步骤就是写测试脚本。由于AdbForAndroid框架是按照元素的相关属性来查找并定位被测对象的,所以首先要弄清楚我们要操作的跨进程的界面上的对象的信息,这些信息我们可以通过很多现成工具来看,我这里选择android自带的uiautomatorviewer。先在模拟器上手工打开被测程序,进入拍照的相机界面,并用uiautomatorviewer查看界面元素信息如下图(3)所示:


图(3)

 

我们可以看到,我们要点击的拍照按钮的属性在图(3)的右下角的列表中已全部展现出来。那么我们该选哪个呢?这个问题取决于adbForAndroid框架支持由哪些属性来获取元素。通过查询其帮助文档,我们知道目前这个框架中常用的查找元素的方法如下:

  • findElementByContentdesc
  • findElementByClass
  • findElementByText
  • findElementById

由于我现在使用的模拟器版本为4.2.2,所以uiautomatorviewer无法显示id属性,如果大家用的是4.3版本以上,就可以看到元素的id属性了。

 

那么现在这种情况来看,我们最好就选择Contentdesc属性来定位对象了。代码很简单,如下:

Element element =position.findElementByContentdesc("Shutter button");

adbDevice.tap(element);  //点击拍照按钮

好,接下来点击了拍照按钮之后,拍照功能还会让你选择是确定还是取消操作,如下图(4)所示:


图(4)

那么如法炮制,我们通过查询获知,这个用于确定的“√”按钮,它的属性能用于定位的其实只有class属性。不过这里要注意的是,此时由于我们用的是class属性,大家可以看到界面上class属性跟我们要点击的“√”这个按钮相同的对象很多,所以我们必须用findElementsByClass方法了。这个方法返回的是一个ArrayList<Element>,所以我们可以写如下的代码来获取所有class属性为”android.widget.ImageView”的元素列表。

ArrayList<Element> imageViews =position.findElementsByClass("android.widget.ImageView");

好,写完之后,现在问题来了,究竟这个数组里面哪个index才是对应的我们要点击的“√”按钮呢?经过试验,我发现界面上多个相同元素返回到数组中时,对应元素位置是按照界面上的位置从上到下、从左到右来的,所以我们要点击的这个按钮的index应该是4。所以点击它的代码如下:

adbDevice.tap(imageViews.get(4));    //2是x,3是重拍,4是√

上面的代码运行完后,界面就会回到我们的被测程序,后面的操作就不用我再多说了,大家看看是不是非常简单?大笑

 

例子2、跨进程操作之打电话

有了第一个例子的基础,其实第二个例子就很好实现了。被测程序非常简单,如下图(5)所示:


图(5)

点击“拨打该号码”后,系统自动进入拨号界面,所以也是典型的跨进程测试场景。

 

实现方法还是跟例1中一样,先还是用uiautomatorviewer查看界面中的对象信息,再使用对应的方法来操作对象即可。而且在这个例子中,我还给大家演示了另外一种情况,即有些跨进程操作不但要进行操作,还要取得一些对象属性来进行验证,这也是基本可以的。这里我直接给出我的测试代码(稍微封装了一下):

public boolean CallUtil(String callNumber){
        Element  element;
        boolean  result;
        //验证是否拨打了正确的号码
        if(callNumber.length() == 11){//正常号码需要转变为 x xxx-xxx-xxxx的格式
                StringformatCallNumber = callNumber.substring(0, 1) + " " +callNumber.substring(1, 4) + "-" + callNumber.substring(4,7) +"-" + callNumber.substring(7, callNumber.length());
                element= position.findElementByText(formatCallNumber);
                try{
                        Thread.sleep(2000);  //线程休眠2秒
                }catch (InterruptedException e) {
                        e.printStackTrace();
                }
        }else{
                element= position.findElementByText(callNumber);//除正常号码外,其他格式的号码不进行格式转换
        }
        if(element != null){
                result= true;
        }else{
                result= false;
        }
        element= position.findElementByContentdesc("End");   //挂断电话
        if(element != null) adbDevice.tap(element);
        return  result;
}

好了,整个过程非常简单。我相信能用robotium的童鞋用起来应该都没有任何问题,所有代码都是非常易用易懂的。

 

相信通过前面的实例,大家可以发现说这是“史上最简单”的Robotium跨进程操作解决方案我估计没人会反对,这并不是夸大事实、博人眼球,确实很简单,功能也很强大。其他也不用我多说了,最后我再来对该框架总结一下下吧:

优点:

1. 确实非常全,基本封装了adb的所有常用命令,它本身就是一个adb命令使用大全了。

2. 框架接口设计清晰易懂,简单明了,封装成jar包,用起来也很方便。另外希望大家都能看看它的源码并了解它的实现细节,作者封装得还是很不错的,很值得我们学习,而不仅仅是简单地使用它。

 

目前已知的不足:

1. 手机的版本必须是4.1以上,即至少必须支持uiautomator的手机才行,因为该框架本身底层是依赖于uiautomator来dump出对象布局xml文件,最终获取对象的坐标进行操作的,所以你的手机版本本身并不支持uiautomator的话,就没法实现dump操作。

2. 如果是真机的话,必须要root后的才可以。

2. 有些对象是uiautomator也无法识别和操作的,那当然这个框架也无能为力了。比如屏幕最上方的通知消息栏的对象,所有工具都没法显示和识别,这个肯定没办法了,另外还比如输入文字时的弹出键盘上的按钮对象等,也无法识别,大家可以试试。

 

以后想要尝试的改进:

1. 对于手机版本的支持问题,个人觉得有个曲线救国的方法可以解决。即我们可以稍微修改下源码,加入判断手机版本的代码,判断当前手机版本如果高于4.1,就直接通过uiautomator来dump,如果低于4.1,则读取PC上事先导出到指定位置的xml文件。这样的话,如果你使用的手机不是4.1以上的版本,只需要事先把被测应用用4.1以上版本的手机通过uiautomator先dump到PC的一个指定路径上就行了,这样效果应该是一样的,只要最终能得到对象坐标就OK。

2. 再加一些比较实用的功能。比如现在可以根据text来查找对象,但实际上很多时候我们可能是得到对象了,但想通过这个对象去获取对象的其他属性,所以建议增加类似getXXXXByElement(Element e)这样的方法,有空试一下,呵呵。

 

以上只是我的一些个人想法,如果大家还有一些什么别的建议,也欢迎大家都提出来,一起来完善这个很实用的框架。

 

最后,再次感谢AdbForAndroid框架的作者: xuxu。

想要研究框架源码的童鞋,可以去github地址下载:https://github.com/gb112211/Adb-For-Robotium

本文中相关样例工程源码(含被测程序和测试程序)下载

另外,如果实在不知道怎么用这个框架的童鞋,可以参考下光荣之路的美女讲师的视频,里面有讲怎么去用这个框架:http://pan.baidu.com/s/1i3raNv3?qq-pf-to=pcqq.group

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

史上最简单Robotium跨进程操作实践——基于ADB框架 的相关文章

随机推荐

  • 速腾聚创雷达最新驱动安装(包含ring和timestamp)运行lio-sam

    记录一下搞slam的过程 ring和timestamp 最近想跑lio sam 需要用到ring和timestamp两个参数 lio sam作者用的velodyne雷达是带这两个参数的 但是rs雷达的老版驱动录制的点云包没有这两个参数 在g
  • pandas分析数据的案例

    1 pandas分析电影数据的案例 https blog csdn net houyanhua1 article details 87858575
  • 共享停车位

    随着代步车的普及 对停车位的需求日益增长 停车位的供应跟不上汽车保有量的快速增长 地段有限 停车场有限 停车位有限 停车难已经成为当今 城市病 中最难解决的一环 随着共享经济的发展 错时停车的提出和实施也逐渐被大众接受 通过物联网创新技术实
  • 服务器自动备份怎么做,服务器运维技巧分享,用backup为数据库做定时备份

    写了套网站 除了日志需要定时分割外 数据库还需要定时备份 如果你用的是云服务器自带的备份功能 会更简单些 但也需要自行购买数据库服务器 对于像我这种还在初期的系统来说 能减少服务器的开支就一定要减少 毕竟现在还不挣钱 安装 用的是ruby
  • Ubuntu20 安装Ceres库和g2o库

    此文章主要适配视觉SLAM十四讲 Ubuntu20 04的情况 建议Ceres版本为2 0 0 g2o库为最新版 安装Ceres库 安装依赖 sudo apt get install liblapack dev libsuitesparse
  • JsonNode与java相互转换

    将Jackson JsonNode数组转换为Java List string JsonNode jsonNode getJsonPayload JsonNode partial jsonNode path someArrayField Li
  • 动态规划(C语言)

    一 入门 以斐波那契数列为例 它的第一项为1 第二项为1 从第三项开始 每一项的值都是前面两项的和 让我们求第n项的是多少 对于这个问题 我们从最开始的递归思想来看 int fib int n if n 1 n 2 return 1 ret
  • js对象的属性用中括号表示

    中括号运算符总是能代替点运算符 但点运算符却不一定能全部代替中括号运算符 中括号运算符可以用字符串变量的内容作为属性名 点运算符不能 中括号运算符可以用纯数字为属性名 点运算符不能 中括号运算符可以用js的关键字和保留字作为属性名 点运算符
  • RISC-V、ARM和X86架构

    1 要了解X86 ARM和RISC V架构的区别 就得先了解复杂指令集 CISC 和精简指令集 RISC A X86使用的是复杂指令集 CISC ARM和RISC V使用的是精简指令集 RISC 这便是属于这几种架构之间最大的区别 狭义的x
  • javaweb使用Thymeleaf 最凝练的CRUD项目-上

    目录 最凝练的CRUD 1 建模 物理建模 逻辑建模 2 总体架构 3 搭建持久化层所需环境 导入jar包 创建jdbc properties 创建JDBCUtils工具类 BaseDao 4 搭建表述层所需环境 导入jar包 创建View
  • 力扣(19) - 跳跃游戏

    给定一个非负整数数组 nums 你最初位于数组的 第一个下标 数组中的每个元素代表你在该位置可以跳跃的最大长度 判断你是否能够到达最后一个下标 示例 1 输入 nums 2 3 1 1 4 输出 true 解释 可以先跳 1 步 从下标 0
  • a*算法的优缺点_轻松理解机器学习算法-朴素贝叶斯

    1 预备知识 贝叶斯定理 Bayes theorem 是概率论中的一个定理 它跟随机变量的条件概率以及边缘概率分布有关 通常事件A在事件B发生的条件下的概率 与事件B在事件A发生的条件下的概率是不一样的 然而这两种是有确定关系的 这种关系就
  • ASP.NET Core 简介

    NET Core 是 NET Framework 的新一代版本 是微软开发的第一个具有跨平台 Windows Mac OSX Linux 能力的应用程序开发框 ASP NET Core 是 Microsoft 新开发的 基于 NET Cor
  • JSON

    数据提取之JSON与JsonPATH JSON JavaScript Object Notation 是一种轻量级的数据交换格式 它使得人们很容易的进行阅读和编写 同时也方便了机器进行解析和生成 适用于进行数据交互的场景 比如网站前台与后台
  • 20181220_eglSwapBuffers详解

    eglSwapBuffers详解 问题来自eglSwapBuffers是否有等待 如果调用eglSwapBuffers的话 是不是会导致帧率下降 2 7 1 BootAnimation中的调用 之所以需要了解这个api的具体实现 因为我们需
  • 标准DH建模与改进DH建模(二)—— 什么是改进DH法以及为什么要学?

    学习机器人建模并不是一个愉快的过程 不愉快的一个重要原因就是 建模得到的方程又臭又长 仅仅是计算一次也许都要花不少时间 更不要说除了正逆运动学方程 你还要需要动力学方程 甚至动力学参数标定方程 当你掌握了DH建模方法后 你会陷入短暂的满足感
  • Python APP自动化测试详解

    一 App自动化测试简介 随着移动互联网的发展 越来越多的App产品应运而生 很多公司除了Web产品外还研发了相应的手机App产品 一些公司的主营业务甚至就是App 测试工程师也需要掌握一定的App端测试技能 从而让自己从烦琐 重复的 点点
  • HTTP Status 500 - An exception occurred processing JSP page /WEB-INF

    HTTP Status 500 An exception occurred processing JSP page WEB INF test showCountry jsp at line 11type Exception reportme
  • 支付宝同步跳转和异步通知简要介绍

    支付宝同步跳转和异步通知简要介绍 同步跳转文件 return url php 异步通知文件 notify url php 用户支付完之后会直接执行return url php 只执行一次 我们在这个文件里写的代码用于修改数据库订单状态 改为
  • 史上最简单Robotium跨进程操作实践——基于ADB框架

    楼主原创 分享不易 转载请注明出处 谢谢 2015年2月3日更新 有些朋友在用真机尝试本方法时 抛出了InputStream cannot be null的异常 该异常是由于adb运行在robotium框架中时 是完全运行在手机中的 此时它