Android系统应用单元测试之路
普通应用单元测试原理
AndroidJUnitRunner组件进行单元测试原理:
1..被测包按debug配置进行打包(用debug进行签名),push到设备中进行安装。
2.通过gradle配置将依赖的包,代码,测试框架,以及自动编写Androidmanifest一起打包到apk中,自动用debug进行签名。(用户有配置自己的debug签名则用用户配置的,没有则用系统默认的)。
push到设备中进行安装。以下为一个实例的Androidmanifest文件。
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.app.test">
<uses-sdk
android:minSdkVersion="17"
android:targetSdkVersion="25" />
<instrumentation
android:label="Tests for com.app"
android:name="android.support.test.runner.AndroidJUnitRunner"
android:targetPackage="com.app"
android:handleProfiling="false"
android:functionalTest="false" />
<application
android:debuggable="true">
<uses-library
android:name="android.test.runner" />
</application>
</manifest>
3.通过系统命令am指挥组件进行测试操作。测试app通过远程调用,以及反射的原理获取被测app的信息来进行测试。
是否可以使用AndroidJUnitRunner和普通应用一样进行单元测试?
1.由于Android Studio已经集成了各种测试操作,可以直接来操作试试。
结果是:系统的应用安装不了,提示版本过低。理论上应该不是版本过低,但系统应用确实没法这样安装,原因是已经有一个系统应用在设备中了,没法安装这个debug签名的应用。这个操作实际上是调用adb uninstall,其实也就是pm uninstall。
那你一定想过那我可以利用root权限,在我定制的系统上把系统应用卸载了再安装这个。理论上不行的。这个系统应用如果签名用了debug那就应该是全部的系统应用都用debug了。否则这个系统应用去访问其他系统应用也就和原来的处理结果不一样了。
2.那我跳过第一步我能不能用我这个debug签名的测试应用直接去测试系统应用呢?
选择不直接测试操作,直接安装测试apk。
安装OK。检查组件是否已安装:
pm list instrumentation
如果没有安装成功,可以用命令试试:
adb push mytest/app-debug-androidTest.apk /data/local/tmp/com.app.test
adb shell pm install -t -r "/data/local/tmp/com.app.test"
安装成功
3.继续直接用命令测试
am instrument -w com.app.test/android.support.test.runner.AndroidJUnitRunner
注意组件/
后面的是在Gradle defaultConfig中配置的
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
测试工程的manifest中也已生成
<instrumentation
android:name="android.support.test.runner.AndroidJUnitRunner"
...
结果:
rvice.test/android.support.test.runner.AndroidJUnitRunner <
INSTRUMENTATION_STATUS: id=ActivityManagerService
INSTRUMENTATION_STATUS: Error=Permission Denial: starting instrumentation ComponentInfo{com.gs.service.test/android.support.test.runner.AndroidJUnitRunner} frome
INSTRUMENTATION_STATUS_CODE: -1
java.lang.SecurityException: Permission Denial: starting instrumentation ComponentInfo{com.gs.service.test/android.support.test.runner.AndroidJUnitRunner} from e
at android.os.Parcel.readException(Parcel.java:1683)
at android.os.Parcel.readException(Parcel.java:1636)
at android.app.ActivityManagerProxy.startInstrumentation(ActivityManagerNative.java:4660)
at com.android.commands.am.Am.runInstrument(Am.java:889)
at com.android.commands.am.Am.onRun(Am.java:400)
at com.android.internal.os.BaseCommand.run(BaseCommand.java:51)
at com.android.commands.am.Am.main(Am.java:121)
at com.android.internal.os.RuntimeInit.nativeFinishInit(Native Method)
at com.android.internal.os.RuntimeInit.main(RuntimeInit.java:294)
可见签名不同无法测试。
其他思路
1.直接在原始被测包中增加测试代码,直接在原始测试包中跑测试用例。测试代码独立出来,尽量不要影响原始代码。跑测试工程时选择不同的Android.mk进行测试。(可以自己搭框架,否则就是利用android测试jar包中的部分代码。不太清楚能否直接用他们的输出覆盖率)
2.系统应用是否有专门的签名,测试包也需要换成相同的签名
3.放弃单元测试。系统应用本身是给普通应用用的,直接进行系统测试。对外接口测试。
以上思路中最佳的就是2.我们顺着2的思路继续解决。
系统应用签名
系统应用用mmp编译使用的是Android.mk配置文件,我们可以看到参数:
LOCAL_CERTIFICATE := platform
课件系统应用使用了platform这个名称的签名。参考以下:
https://blog.csdn.net/cxq234843654/article/details/51557025
生成一个platform的签名。并使用它在android中跑。我们发现可以用AndroidStudio进行安装测试了。
其他
我自己还碰到报错版本过低。自己以为版本是对的。但还是报错。最佳的还是要看android系统的logcat。
使用logcat -c清log,再安装一遍,再logcat查看具体原因。就能发现当下版本号多少,系统已安装的版本号多少。