收集Android程序测试代码覆盖率
代码覆盖率的作用主要是用来查看测试用例执行完毕后,有哪些代码尚未覆盖到,未覆盖到的代码通常意味着未覆盖到的功能或场景,对于Andriod程序来说,好像国内聊到这个领域的文章不多,这里记录下来供大家参考。
因为Andriod程序实际上就是Java程序,这里先不谈Andriod native C程序的代码覆盖率收集(后面的文章会讲到,其实就是用gcov做的),Java程序的代码覆盖率统计可以使用一个开源软件Emma,Emma并不需要源码就可以统计代码覆盖率 。这是因为统计代码覆盖率的做法有两种(参看以前的文章:):
1、修改程序源代码,添加统计代码覆盖率的代码,例如gcov采用的就是这种做法。
2、修改最终程序,比如Emma就是修改Java class的字节码Oolong代码。为了能够将统计到的代码覆盖率结果追溯到源代码,一般是将Java编译成调试(Debug)版,做法是:Emma在每个Oolong跳转代码前加入统计覆盖率的代码,而调试版的class,里面会有.source, .line. .var这些指令,告诉调试器字节码与Java源代码、Java变量与Oolong变量的数字引用的映射关系,这种做法的好处是,只要你的程序最终会生成Java字节码,例如Scala之类的程序,生成的调试版都可以用Emma修改,达到统计代码覆盖率的目的。Java虚拟机对调试的支持,请参考书籍《Programming for the Java™ Virtual Machine》第7章里的描述。
因为Andriod程序在部署到设备之前,会有个程序(dx)将Java字节码翻译成Andriod虚拟机里的字节码,所以可以在翻译之前使用Emma修改class文件,再打包。
实际上Andriod提供了一个ant的 build文件,里面就封装了这个功能,我这里将这个脚本做的事情挖了出来,解释一下各步骤。在解释之前,先看看如何用ant编译一个覆盖率统计版:
1、从eclipse的andriod工程里生成一个ant的build文件,andriod-app就是工程名:
android update project -p android-app
2、将eclipse的andriod测试工程也转换成ant工程,-m选项指定了测试工程对应的主andriod工程的位置,而android-test就是测试工程名:
android update test-project -m ../android-app -p android-test
3、执行下面的命令,编译、执行单元测试、收集覆盖率:
ant clean emma debug install test
4、在设备上,/data/data/<package name>/目录里,有一个files文件夹里有coverage.ec文件,即记录了代码覆盖率信息,但这个信息还需要跟源码做一次映射才能看到哪些代码行已覆盖。
5、将上面coverage.ec文件拷贝到andriod主工程的bin文件夹里,这个文件夹里有一个文件名coverage.em,里面记录了修改过的字节码与源代码的映射关系。
6、要查看代码覆盖率时,执行下面的命令(andriod SDK里以及自带了emma.jar),下面命令里的sp参数即指定了 源代码的位置:
java -cp ~/android-sdk/tools/lib/emma.jar emma report -r html -in coverage.em -in coverage.ec -sp ~/<andriod-app>/src/
这里我们把ant命令分解(假设已经将andriod eclipse工程转换成ant工程了),实际上执行下面几个命令就可以了,下例中~/research/multiplatformdemoproject就是andriod的主工程路径:
cd ~/research/multiplatformdemoproject/
# 编译成调试版
ant debug
# 在打包成dex文件之前,修改class字节码
cd bin
java -cp ~/android-sdk/tools/lib/emma.jar emma instr -ip classes -d instrumented
# 将修改成覆盖率统计版的class字节码打包成andriod虚拟机文件
~/android-sdk/platform-tools/dx --dex --debug --no-optimize --output=classes.dex instrumented
~/android-sdk/platform-tools/aapt package -v -f -M /home/shiyimin/research/multiplatformdemoproject/AndroidManifest.xml -S /home/shiyimin/research/multiplatformdemoproject/res -I /home/shiyimin/android-sdk/platforms/android-8/android.jar -F multiplatformdemoproject.unsigned.apk /home/shiyimin/research/multiplatformdemoproject/bin/
# 签名
jarsigner -keystore ~/.android/debug.keystore -storepass android -keypass android -signedjar multiplatformdemoproject.signed.apk multiplatformdemoproject.unsigned.apk androiddebugkey
~/android-sdk/tools/zipalign 4 multiplatformdemoproject.signed.apk multiplatformdemoproject.apk
# 部署主程序到设备上
~/android-sdk/platform-tools/adb install multiplatformdemoproject.apk
# 编译测试用例
cd tests
ant debug
# 部署并且执行测试用例
~/android-sdk/platform-tools/adb install multiplatformdemoproject.test-debug.apk
~/android-sdk/platform-tools/adb shell am instrument -w -e coverage true cc.iqa.studio.demo.test/android.test.InstrumentationTestRunner
# 查看代码覆盖率结果报告
cd http://www.cnblogs.com/bin/
~/android-sdk/platform-tools/adb pull /data/data/cc.iqa.studio.demo/files/coverage.ec .
java -cp ~/android-sdk/tools/lib/emma.jar emma report -r html -in coverage.em -in coverage.ec -sp ~/research/multiplatformdemoproject/src/
下面是几个截图:
本文转自 donjuan 博客园博客,原文链接: http://www.cnblogs.com/killmyday/archive/2012/07/23/2605708.html ,如需转载请自行联系原作者

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
-
上一篇
CCNA第二天学习笔记之Cisco系统IOS
路由器简介 路由器能起到隔离广播域的作用,还能在不同网络间转发数据包。路由器实际上是一台特殊用途的计算机,和常见的PC机一样,路由器有CPU、内存、BOOT ROM。路由器没有键盘、硬盘、显示器;然而比起计算机,路由器多了NVRAM、FLASH以及各种各样的接口。路由器各个部件的作用如下: 1、CPU:中央处理单元,和计算机一样,它是路由器的控制和运算部件。 2、RAM/DRAM:内存,用于存储临时的运算结果,如:路由表、ARP表、快速交换缓存、缓冲数据包、数据队列、当前配置。众所周知,RAM中的数据在路由器断电后是会丢失的。 3、FLASH:可擦除、可编程的ROM,用于存放路由器的IOS,FLASH的可擦除特性允许我们更新、升级IOS而不用更换路由器内部的芯片。路由器断电后,FLASH的内容不会丢失。FLASH容量较大时,就可以存放多个IOS版本。 4、NVRAM:非易失性RAM,用于存放路由器的配置文件,路由器的配置文件,路由器断电后,NVRAM中的内容仍然保持。 5、ROM:只读存储器,存储了路由器的开机诊断程序、引导程序和特殊版本的IOS软件(用于诊断等有限用途),ROM中软件...
-
下一篇
Android 获取正在运行的任务和服务
要获取正在运行的任务,首先需要声明一个活动对象管理器(ActivityManager) 所有的活动任务都属于此,然后通过获取服务可以得到所有的活动对象,然后通过活动对象可以得到所有运行的任务和服务,当然要获取服务和任务是使用不同的方法,但是方式是一样的。下面是获取代码: 代码: 1 void getTask() { 2 3 ActivityManager activityManager; 4 try { 5 activityManager = (ActivityManager) this 6 .getSystemService(ACTIVITY_SERVICE); 7 8 arylistTask = 9 new ArrayList<String>();10 11 12 13 List<ActivityManager.RunningTaskInfo> mRunningTasks =14 15 activityManager.getRunningTasks(30); //30表示获取的最大数16 17 /* 以循环及baseActivity方式取得任务名称与ID *...
相关文章
文章评论
共有0条评论来说两句吧...