Robotium体验----黑盒&重签名

上篇我们使用了白盒示例,对Robotium进行了简单介绍。但需要提醒的是,Robotium的官方定位还是黑盒测试。那么,我们还是书归正传,看看如何使用Robotium进行黑盒测试。本节,将解决以下几个问题。

(1)如何编写黑盒测试案例
(2)如何设置为同一进程
(3)如何进行重新签名

创建测试对象

在编写测试案例之前,我们先创建一个测试对象。工程名称定义为RobotiumTestObj,launch Activity仍为MainActivity。目录结构如下。

Robotium体验----黑盒&重签名_第1张图片

之后,我们创建keyStore。
keyStore文件的password为123456。
key0的password为abcdef。

Robotium体验----黑盒&重签名_第2张图片

用该keyStore生成对应的签名APK,并安装。

Robotium体验----黑盒&重签名_第3张图片

编写黑盒测试案例

(1)在创建测试类

我们在com.breakloop.robotiumdiary下,创建day2的package,并添加名为BlackBoxTest的类。

接下来是跟白盒测试不同的地方。BlackBoxTest要继承自ActivityInstrumentationTestCase2。

public class BlackBoxTest extends ActivityInstrumentationTestCase2{
....
}

(2)指定测试Activity

该步骤也与白盒测试存在差异。在白盒测试中,使用ActivityTestRule进行指定。而黑盒测试,则是依靠ActivityInstrumentationTestCase2构造函数来指定的。

ActivityInstrumentationTestCase2构造时,需要提供一个class(即activity.class)作为传参。我们可以通过class名称,使用反射获取一个class,再将class传入ActivityInstrumentationTestCase2构造函数。

public static Class forName(String className)
                throws ClassNotFoundException

因此,对于黑盒测试,这里仅需要获取apk的launch activity类名即可。

关于如何获取launch activity名称,需要用到android SDK自带工具aapt.exe。这里不再啰嗦,不清楚的童鞋,可以参照博文http://blog.csdn.net/daihuimaozideren/article/details/78267642。

在测试类中添加相关代码

private static final String LAUNCHER_ACTIVITY_FULL_CLASSNAME = "com.breakloop.robotiumtestObj.MainActivity";

public BlackBoxTest() throws ClassNotFoundException {
    super(Class.forName(LAUNCHER_ACTIVITY_FULL_CLASSNAME));
}

@Override
public void setUp() throws Exception {
    super.setUp();
    Solo.Config config=new Solo.Config();
    config.commandLogging=true;
    config.commandLoggingTag="BlackBoxTest";
    solo=new Solo(InstrumentationRegistry.getInstrumentation());
    getActivity();
}

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

唠叨:
(a) setUp和tearDown类似于JUnit的@Before和After。
(b) getActivity()为ActivityInstrumentationTestCase2的接口方法,用于打开LAUNCHER_ACTIVITY_FULL_CLASSNAME指定的Activity。
(c) getActivity()必须在super.setUp()之后调用。
(d) LAUNCHER_ACTIVITY_FULL_CLASSNAME所指定的Activity,不一定为LAUNCH ACTIVITY。

(3)创建solo实例和测试案例

直接将WhiteBoxTest的相关内容copy,之后做简单修改即可。

public void test1(){
    solo.unlockScreen();
    solo.sleep(1000);
    solo.setActivityOrientation(Solo.LANDSCAPE);
    solo.sleep(1000);
    solo.setActivityOrientation(Solo.PORTRAIT);
    solo.sleep(1000);
}

由于没有使用AndroidJUnit作为Runner,因此测试案例没有使用@Test标注。
ActivityInstrumentationTestCase2的测试案例方法,必须以test开头,区分大小写。

(4)执行测试案例

执行测试案例,结果未如此前白盒测试的效果,报错。日志显示如下,

W/System.err: java.lang.ClassNotFoundException: com.breakloop.robotiumtestobj.MainActivity

为什么呢?

Robotium是对Android Instrumentation的封装,即google的女婿。如果要进行google资源访问的话,需要遵循Instrumentation的规则。
Instrumentation只能对同一进程内,且具有相同签名的资源进行访问。两个条件,缺一不可。
问题明了了。

同一进程

通常情况下,每个APP都是一个进程(当然,开发时,可以通过设置process id的方式,进行多进程设置)。而每个进程都有一个ID。

如果使用Android Studio开发,你会在主模块的build.gradle中看到application id,即为进程ID。

 defaultConfig {
        applicationId "com.breakloop.robotiumtestobj"
        minSdkVersion 18
        targetSdkVersion 26
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }

通常,它与project的package name相同。
Eclipse开发,则没有application id的概念,可以直接使用package name.

那么,在黑盒的情况下,如何获取进程ID呢?Android Device Monitor可以帮忙。
仅需要将重签名的APK(关于如何重签名,之后会记录)安装,并启动,便能在Monitor中看到进程ID(第一列)。

Robotium体验----黑盒&重签名_第4张图片

Robotium体验----黑盒&重签名_第5张图片

获取进程ID后,将其设置为测试工程,主模块的application ID即可(build.gradle中)。

似乎万事俱备了!再次在Android Studio中运行BlackBoxTest。

Robotium体验----黑盒&重签名_第6张图片

结果,再次报错!

W/System.err: java.lang.ClassNotFoundException: com.breakloop.robotiumtestobj.MainActivity

而且,跟之前是同样的问题。为什么?还是因为进程吗?

Android Studio中的附加操作

查看Console,发现每次运行测试,Android Studio都会安装两个APK,一个app-debug.apk,即测试目标;一个app-debug-AndroidTest.apk。

Robotium体验----黑盒&重签名_第7张图片

之所以找不到com.breakloop.robotiumtestobj.MainActivity,是因为安装了错误的测试apk!
即C:\D\proj\robotiumDiary\app\build\outputs\apk\debug\app-debug.apk
而非C:\D\proj\RobotiumTestObj\app\build\outputs\apk\debug\app-debug.apk

每次build,rebuild,Android Studio都会生成自身工程所对应的app-debug.apk,因此,我们需要做的就是让Android Studio对生成的app-dubug.apk进行替换。

替换操作,需要两步。

首先,在测试工程主模块的build.gradle中添加Task,用于完成替换操作。

android {
...
    task copyApk(type:Copy){
        from "C:\\D\\proj\\RobotiumTestObj\\app\\build\\outputs\\apk\\debug\\app-debug.apk"
        into "C:\\D\\proj\\robotiumDiary\\app\\build\\outputs\\apk\\debug"
    }
}

其次,要在运行测试案例前,运行上一步的Task。

Robotium体验----黑盒&重签名_第8张图片

Robotium体验----黑盒&重签名_第9张图片

Robotium体验----黑盒&重签名_第10张图片

再次,运行测试案例。

Test running failed: Permission Denial: starting instrumentation ComponentInfo{com.breakloop.robotiumdiary.test/android.support.test.runner.AndroidJUnitRunner} from pid=23849, uid=23849 not allowed because package com.breakloop.robotiumdiary.test does not have a signature matching the target com.breakloop.robotiumdiary

Activity找到了!但signature是下一关BOSS。

签名机制

每个发布的apk都是具有签名的,即使是Debug版本。Debug版本的keystore文件,位于当前用户的”.android”目录下,文件名为debug.keystore。

注:如果是最新版本的Android Studio,可有在SDK目录下的tools目录找到debug.keystore。跟”.android”目录下内容一致。

Robotium体验----黑盒&重签名_第11张图片

签名会在版本更新时用到。如果没有签名,那么任何人都可以对其他人的作品进行更改。签名,即为非对称加密算法的应用。而所有的签名信息,都包含在apk的META-INF目录中。

我们用zip打开一个apk,并进入META-INF目录。

Robotium体验----黑盒&重签名_第12张图片

MANIFEST.MF:保存了zip包内(除META-INF目录)所有文件所对应的哈希值。所有哈希值,都成对存在,一行Name(文件相对路径),一行SHA1-Digest(即文件的SHA1哈希值)

Robotium体验----黑盒&重签名_第13张图片

CERT.SF:也是一组哈希队列。不同的是,
(a)将MANIFEST.MF也作为了一个计算对象,获取了哈希值,并成对保存了起来。
(b)将MANIFEST.MF中的成对信息,再次计算哈希,跟原有Name配对,再次保存。

Robotium体验----黑盒&重签名_第14张图片

CERT.RSA:对CERT.SF的非对称加密。

因此,如果我们要进行重新签名,仅需要将这三个文件从APK中删除,之后使用debug.storekey重签即可。

重新签名

网上流传两种种常用的签名方法,一种是自动的,一种是手动的。但原理一样。

(1)自动签名

Robotium体验----黑盒&重签名_第15张图片
使用Java(TM) Platform SE binary运行re-sign.jar,然后只需要将apk拖入,并指定生成apk的保存目录即可。生成完毕时,会自动弹出package name和launch activity。

re-sign.jar可以从http://troido.de/downloads/category/1下载。上次更新还是在2014年。
需要注意的是,re-sign.jar需要环境变量的支持。

Robotium体验----黑盒&重签名_第16张图片

jarsigner是JDK自带的签名工具包,就在JDK bin目录下。
zipalign是Android SDK build tool的工具包,用于将编码进行4字节对齐。但该jar包并不存在于Android SDK的tools目录下!可以从Android SDK build tool目录下某一版本中进行拷贝。

Robotium体验----黑盒&重签名_第17张图片

个人在使用re-sign时,吃瘪了。报错ERROR:138。可能还是环境不对,或兼容版本问题。找了许久,就没有合理的解释,于是个人放弃,希望我是个例。
本人用的JDK版本为1.8.0_144,zipalign用的是27.0.3。

当然,自动方式所用软件也不止一种。Robotium Recorder也能够重签名(在用户选择测试APK时,自动生成重签APP,并保存在相同路径下)。

(2)手动签名

其实,re-sign所做的不外乎3件事情,一,删除签名信息。二,使用jarsigner签名。三,使用zipalign对齐。只是re-sign将一切变的简单了。而这些事情,手动一样能够完成。

  • 用zip打开apk,删除META-INF目录,并再次用zip打包为apk。
  • 使用jarsigner签名。
jarsigner -verbose -digestalg SHA1 -sigalg SHA1withRSA -keystore C:\Users\用户名\.android\debug.keystore -signedjar C:\D\proj\RobotiumTestObj\app\release\app-debug.apk C:\D\proj\RobotiumTestObj\app\release\app-release.apk androiddebugkey

唠叨:
-verbose用于显示详细过程。
-digestalg用于指定哈希算法,即MANIFEST.MF和CERT.SF所用的哈希算法。
-sigalg用于指定CERT.RSA所用的签名算法。
-signedjar用于指定重签名后文件的名称和路径,若不提供,则对原文进行重签名操作。
-keystore用于指定keystore文件。
androiddebugkey为keystore文件中的别名。

附加问题来了?忘了keystore的别名怎么办?
答:使用JDK自带的keytool工具查看keystore内容。不仅能看别名,还能看所支持的签名算法。debug.keystore默认口令为:android

keytool -list -v -keystore C:\Users\user\AppData\Local\Android\sdk\tools\debug.keystore

Robotium体验----黑盒&重签名_第18张图片

  • 使用zipalign对齐。该步骤只是为了优化,可有可无。-v 4代表四字节对齐。
zipalign -v 4 C:\D\proj\RobotiumTestObj\app\release\app-debug.apk C:\D\proj\RobotiumTestObj\app\build\outputs\apk\debug\app-debug.apk

至此,签名完成!

运行BlackBoxTest,这时,我们期望的画面出现了。

关于重签的说明

任何apk都可以用上述操作重新签名,但重签后并不代表能够被DEBUG!

Robotium体验----黑盒&重签名_第19张图片

下面是正常启动时的日志,如果Debuggable没有开启,程序会一直“Waiting for application to come online”,直至Timeout。因此,在获取apk时,一定要再三确认!珍爱生命~

Launching BlackBoxTest
$ adb push C:\D\proj\robotiumDiary\app\build\outputs\apk\debug\app-debug.apk /data/local/tmp/com.breakloop.robotiumtestobj
$ adb shell pm install -t -r "/data/local/tmp/com.breakloop.robotiumtestobj"
Success


No apk changes detected since last installation, skipping installation of C:\D\proj\robotiumDiary\app\build\outputs\apk\androidTest\debug\app-debug-androidTest.apk
$ adb shell am force-stop com.breakloop.robotiumtestobj.test
Running tests

$ adb shell am instrument -w -r   -e debug true -e class com.breakloop.robotiumdiary.day2.BlackBoxTest com.breakloop.robotiumtestobj.test/android.support.test.runner.AndroidJUnitRunner
Waiting for application to come online: com.breakloop.robotiumtestobj | com.breakloop.robotiumtestobj.test
Waiting for application to come online: com.breakloop.robotiumtestobj | com.breakloop.robotiumtestobj.test
Connecting to com.breakloop.robotiumtestobj
...

小结

经过了本文的梳理,想要入手的童鞋应该也清楚ROBOTIUM的七寸了。是否继续,做个了断吧~
至此,对于如何保证黑盒测试,应该不在话下了。

你可能感兴趣的:(android测试,Android自动化测试)