移动端自动化测试----Robotium和Robotium Recorder

简介

Robotium是一款国外的自动化测试框架,是一款免费的Android UI测试工具,目前最新的版本是5.6.3,主要针对Android平台的应用进行黑盒自动化测试,它提供了模拟各种手势操作(点击、长按、滑动等)、查找和断言机制的API,能够对各种控件进行操作。Robotium结合Android官方提供的测试框架达到对应用程序进行自动化的测试。

Robotium测试脚本是用java写的,该框架使用简便,支持性良好,支持native和hybird的自动化测试,API使用起来方便简单,执行速度快,可根据控件ID操作,可以自动处理多个Android 的Activity,也可以和Maven、Gradle以及Ant更好的结合,成为可以持续集成的测试;另外它既可以基于源码操作,也能基于APK(无源码)测试,功能强大。

Robotium Recorder是Robotium团队四五年以来对Robotium框架的可持续的创造和改造的成果,可以帮助我们快速的录制Java脚本(收费),而且录制好的脚本经过适当的完善修改就可以输出稳定的测试用例,遗憾的是目前该服务是收费的,仅仅能体验一下。

Robotium官网:https://github.com/RobotiumTech/robotium

Robotium API 简介官网:http://recorder.robotium.com/javadoc/

Robotium自动化测试的原理

Robotium是基于instrumentation的二次封装。Roboiutm分查找控件和点击控件两大类操作。查找控件的原理是:在waitter的waitForView()方法里面通过java反射获得视图,并匹配所需要的控件,查找并返回控件对象。点击控件的原理是:查找到的控件对象解析包装成MotionEvent,基于Instrumentation框架,通过InputManager注入事件。调用类组织结构如下图简示:

image.png

Robotium自动化工程----黑盒(基于APK(无源码)的自动化测试)

测试步骤:

1.创建Android工程

​ 要和测试的APK同包名,同签名 , 虽然安装到手机上仍然会识别为两个应用,但是如果测试应用和待测应用同时运行,由于他们具有相同的数字签名,Android系统的Instrumentation可以将它们加载到同一个进程中运行,这样的话,测试代码就可以获取到待测应用的数据,更为详细的过程可以研究系统的测试框架Instrumentation。

Robotium框架需要被测应用和测试工程需要使用相同的签名,这样才可以使用Instrumentation把被测应用启动起来

APK重签名:在基于APK的自动化测试过程中,需要确保被测试的APK必须与测试项目具有相同的签名。利用工具re-sign.jar,用法可自行baidu。(re-sign重签名找的debug.keystore)

重签名工具:re-sign.jar

2.配置Gradle

工程目录的build.gradle中添加依赖

如果需要使用Robotium,就必须使用android.test.InstrumentationTestRunner。简单讲,Instrumentation框架是android测试环境 的核心,在这个框架下,测试应用程序 可以精确控制应用程序。它可以理解为 一种没有图形界面的,具有启动能力的 ,用于监控其他类的工具类,其中的关键类就是InstrumentationTestRunner。

android {
    ...
    defaultConfig {
        ...
        testInstrumentationRunner "android.test.InstrumentationTestRunner"
    }
}

dependencies {
    ...
    androidTestCompile 'com.jayway.android.robotium:robotium-solo:5.6.3'
}

在浏览器中搜索maven仓库,搜索robotium,选择最新版本,切换到gradle下,把包名:名称:版本添加到dependencies中(以冒号分隔)

image.png

3,写测试代码并打包

本工程项目主要是写测试代码(针对APK),所以在androidTest/java/包下写代码,Android代码不用理会。写完测试代码后,执行命令打包测试apk。

image.png

robotium是基于ActivityInstrumentationTestCase2的二次封装,测试方法都需要继承父类。每个测试类都是以setUp开始,以tearDown结尾,中间再添加各个test case。

在测试包下面创建一个测试类,命名规范为XxxTest,该类继承ActivityInstrumentationTestCase2,构造方法中需要传入app的启动activity。

例子:在该项目下创建一个包,com.example.demo1.test,在该包下创建TestDemo1Apk类,

代码如下:

package com.example.demo1.test;
 
import com.robotium.solo.Solo;
 
import android.test.ActivityInstrumentationTestCase2;
import android.widget.EditText;
 
@SuppressWarnings("rawtypes")
public class TestDemo1Apk extends ActivityInstrumentationTestCase2 {
 
        private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.example.demo1.MainActivity";//启动类
 
        private static Class<?> launcherActivityClass;
        static{
         //通过反射的方式获取的
                try {
                        launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
                } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                }
        }
         
        @SuppressWarnings("unchecked")
        public TestDemo1Apk() throws ClassNotFoundException {
                super(launcherActivityClass);
        }

        private Solo solo;

以上就设置好了启动的activity,然后需要重载两个方法

public void setUp() throws Exception;
public void tearDown() throws Exception;

setUp()做一些启动测试前的准备工作,如创建Solo实例,启动activity等

@Override
    public void setUp() throws Exception {
        super.setUp();
        //创建Solo实例
        solo = new Solo(getInstrumentation());
        //启动activity
        getActivity();
    }

tearDown()中测试做一些善后的工作,如结束activity等

  @Override
    public void tearDown() throws Exception {
        solo.finishOpenedActivities();
        super.tearDown();
    }

上述工作准备好之后,剩下的就是我们的测试主体方法了。方法格式如下:

public void testcase001() {
}

代码整合:

package com.example.demo1.test;
 
import com.robotium.solo.Solo;
 
import android.test.ActivityInstrumentationTestCase2;
import android.widget.EditText;
 
@SuppressWarnings("rawtypes")
public class TestDemo1Apk extends ActivityInstrumentationTestCase2 {
 
        private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.example.demo1.MainActivity";//启动类
 
        private static Class<?> launcherActivityClass;
        static{
         //通过反射的方式获取的
                try {
                        launcherActivityClass = Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME);
                } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                }
        }
         
        @SuppressWarnings("unchecked")
        public TestDemo1Apk() throws ClassNotFoundException {
                super(launcherActivityClass);
        }
         
        private Solo solo;
         
        @Override
    public void setUp() throws Exception {
        super.setUp();
        //创建Solo实例
        solo = new Solo(getInstrumentation());
        //启动activity
        getActivity();
    }

 
 
        public void testcase001()  {
  
             //测试用例
        }
         
 
  @Override
    public void tearDown() throws Exception {
        solo.finishOpenedActivities();
        super.tearDown();
    }
 
 
}

实战-针对工作目录下的项目

最基础的测试用例框架类

package com.example.demo1.test;
 
import com.example.demo1.MainActivity;//导入目标项目的启动类
import android.test.ActivityInstrumentationTestCase2;
import com.robotium.solo.Solo;
 
 
public class TestDemo1 extends ActivityInstrumentationTestCase2<MainActivity>{//继承目标项目的启动类
 
    private Solo solo;//初始化一个solo对象
 
    public TestDemo1() {//在构造函数处标明继承自目标项目的启动类
        super(MainActivity.class);
    }
     
    @Override
    public void setUp() throws Exception {//在测试开始之前会调用这个方法,这里来创建一个Solo对象
        super.setUp();
        solo = new Solo(getInstrumentation(), getActivity());
    }
    
    public  void  testcase001(){

//测试用例
  }
   
    @Override
    public void tearDown() throws Exception {//一个测试用例结束的时候会调用这个方法
        solo.finishOpenedActivities();//这个方法将结束掉所有在测试执行过程中打开的activity
        solo.tearDown();
    }
 
 
 
}
image.png

4.安装apk进行测试

①安装待测apk

adb install 待测apk路径
安装完毕后,可以执行命令,来查看是否安装上了对应的InstrumentationTestRunner
adb shell pm list instrumentation
结果中会列出手机上安装的所有的instrumentation测试程序,找到自己的,看是否正确:
instrumentation:包名.test/android.test.InstrumentationTestRunner (target=包名)

image.png

Ttips:如果你发现你的使用的是Android.support.test.runner.AndroidJUnitRunner,则表示没有配置 testInstrumentationRunner "android.test.InstrumentationTestRunner",这个是Android Studio默认的JUnitRunner,进行junit测试的,需要在gradle中修改掉。

②安装用于robotium测试的apk

adb install 测试apk的路径
可以执行命令列出所有的第三方应用,查看两个包是否安装成功,其中待测spk的包名为:"包名.test"
adb shell pm list packages -3

③开启测试

adb shell am instrument -w 包名.test/android.test.InstrumentationTestRunner
稍等片刻,首先会启动测试程序,测试程序会去启动被测应用,然后模拟点击和输入,最终给出简单的测试结果。

Robotium自动化工程----白盒(基于源码操作)

1.创建Android项目

2.安装Robotium插件

在android studio中集成Robotium和集成其他的插件一样,File->Setting->Pluygins-Browse repositories,输入robotium,找到Robotium Recorder并点击安装,安装完重启即可。然后,该插件就会出现在Tools菜单中:

image.png

3.启动插件

安装完插件以后,使用ADB连接上手机或者模拟器,并且设备必须有外部存储。

点击Tools菜单中的Robotium Recorder,出现该插件的对话框,

image.png

此时选择有两个:

①点击”select apk”,选择APK,然后点击”Next”,最终会在本项目工程中创建一个module用来测试,此时做的就是黑盒测试;

②在中间的框内会出现本工程中包含的module,选中之后,该插件会自动打包成apk文件,点击”Next”,最终默认会在选中的module中的测试文件夹下生成测试用例,此时就是白盒测试。从测试的角度讲就是关联了源代码,从开发的角度讲,就是相当于单元测试。需要注意的时候,由于是该插件打包的,所以默认使用的是本地的原生的签名配置文件。

4.开始录制脚本

点击“Next”之后就会出现下面的对话框,先看一下Setting目录:


image.png

4.1 Runtime options 运行时配置

  • Use sleeps - 是否会使用sleeps方法,来保证回放测试用例的速度和录制的时候相同,该配置对那些带宽密集型或者混合App特别有用。简单讲,就是在生成的测试用例中调用sleep()方法来模拟用户录制时的操作间隔,如果不设置的话,该recorder只会捕捉到用户和Activity的动作,但是回放的时候会顺序瞬间执行。
  • Keep app data - 如果开启一个新的脚本录制的时候,是否保留App的数据。
  • Click and drag coordinates - 选择在点击和拖拽的时候是否录制坐标。

4.2 Saved path - SDK和JDK路径

4.3 License key - 证书(购买后才会下发邮件)

image.png

此时点击”New Robotium Test”就会自动进行开始脚本录制,流程如下:

1.打APK包
    adb shell am force-stop xxx
2.将APK包push到设备上
    adb push xxx.apk /data/local/tmp/xxx
3.从设备上安装APK包
    adb shell pm install -r "/data/local/tmp/xxx"
4.运行测试用例:
    adb shell am instrument -w -r -e debug false -e class xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

这些过程在控制台都可以看得到,会输出原始的命令,有利于我们了解robotium的整个流程。

当程序成功的安装到设备上并启动之后,在插件的对话框界面就可以看到有Activity启动了,然后就可以进行一些测试的操作,你会发现在该对话框中就会记录出操作的整个过程,比如打开了那个界面、点击了某个按钮、输入了什么内容等,这些都会转换成java测试代码,下次运行测试用例的时候,就会按照这个顺序进行测试。

5.保存脚本

测试结束后,点击Save,起个名字,就会自动生成测试脚本类,保存在src/androidTest目录中。

首先简要的分析一下该类:

  • 继承了ActivityInstrumentationTestCase2类,该类在android.test包下,泛型指的是需要进行测试的类,图中为登陆的测试用例,所以第一次打开的是SplashActivity。其实Robotium内部就是对Android的Instrumentation进行了2次封装,使其变得更加方便。

  • Robotium内部集成了Junit3,所以对junit熟悉的很容易看懂一些基本特点:setUp()启动测试用例、tearDown()测试结束、testRun()就是本测试用例中的一个测试过程,

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容