JAVA代码覆盖率工具JaCoCo-踩坑篇

SusSoper 8年前
   <h2>一、覆盖率踩过的坑</h2>    <p>在项目中使用JaCoCo覆盖率的时候,也遇到过各种奇葩的问题,在这里列出来分享下,问题和实际的项目关系密切,希望对有遇到过相似问题的童鞋有所启发。</p>    <h2>1.1 覆盖率包在部分手机6.0上安装失败</h2>    <p>事情起因:在测试新功能时,用打的覆盖率包,外包反馈部分手机6.0上安装不了。</p>    <p>问题重现:试了在自己的手机,华为mate8的6.0系统上安装正常,属于部分机型问题。</p>    <p>将问题小米手机借来后,发现用豌豆荚或者应用宝确实安装失败,提示“该应用签名有问题,无法安装。”通过adb install安装,提示INSTALL_PARSE_FAILED_NO_CERTIFICATES</p>    <p>怀疑是部分厂商对签名的校验级别比较高。</p>    <p>问题排解:</p>    <p>(1)网上有种说法,jdk1.7以后变更了默认的加密算法,而签名程序没有,所以需要在签名时用参数指定。</p>    <p>具体方法:在签名命令后加入-digestalg SHA1 -sigalg MD5withRSA</p>    <p>会不会这种情况导致:查了应用宝的打包脚本,签名部分已经增加。</p>    <p><img src="https://simg.open-open.com/show/9182ab58983abde584355930cce7ead9.png"></p>    <p>此种情况排除</p>    <p>(2)会不会签名文件有问题?</p>    <p>重新排查了打包过程的签名,密钥和口令都和RDM打包一样,对ANDROIDR.RSA、ANDROIDR.SF、MANIFEST.MF,清除掉签名,重新进行签名,问题仍然存在。</p>    <p>此种情况排除</p>    <p>(3)JaCoCo的jar包重新签名</p>    <p>和RDM打包,也就增加了JaCoCo部分,会不会是JaCoCo的两个jar包jacocoagent.jar和jacocoagent.jar出的问题?</p>    <p>这两个jar包已经是签名过的,会不会需要用应用宝的签名进行重新签?</p>    <p>使用jarsigner重新对这两个jar包用应用宝的密钥进行签名,打包安装,问题仍然存在。</p>    <p>此种情况排除</p>    <p>到这里,网上的各种方法基本都试过了,没任何效果,问题纠结在这里了。</p>    <p>静下心来,网上的方法没任何效果,还是回到项目中,重新一步一步的对比RDM打包和覆盖率打包的区别,逐步排查吧。</p>    <p>(4)RDM打包和覆盖率打包逐一对比</p>    <p>….(这里省略一万字,都是排查)</p>    <p>签名部分的日志对比:</p>    <p>我们还是回到打包签名的target:sign_obfuscated</p>    <p>逐行对比RDM和我们覆盖率打包的日志:</p>    <p>发现了一个不同的点:</p>    <p>RDM的:</p>    <p><img src="https://simg.open-open.com/show/95dcf2d0b71f701f3918d11f9f371f91.png"></p>    <p>我们打包的:</p>    <p><img src="https://simg.open-open.com/show/6e2f4732218b2bc8e5e561d12112f9cb.png"></p>    <p>大家看出差别了没(红色部分)</p>    <p>红色部分为jacocoagent.jar包里的非class文件,signer对这两个文件也进行了签名。</p>    <p>到这里都不是问题。</p>    <p>问题还是应用宝脚本本身(┬_┬哭~)</p>    <p><img src="https://simg.open-open.com/show/d13d6614bec0afebb0565e71173607e6.png"></p>    <p>签名后做compress和zipalign,据说是极限压缩,减少包的大小。</p>    <p>Compress会调用compress_yingyongbao.sh脚本,这里列出了所有要压缩的文件</p>    <p><img src="https://simg.open-open.com/show/00ec3c90ec94fc524b2827cad2dedb9e.png"></p>    <p>看到没,看到没,它重新按这里的文件列表压缩打包,丢掉了上面JaCoCo里面的两个文件</p>    <p>应用在打包后,签名文件是存在JaCoCo这两个文件的,但打包后找不到这两个文件,因此安装时有的手机提示签名有问题。</p>    <p>解决方法:</p>    <p>JaCoCo这两个文件,一个是属性文件,一个是生成xml的dtd文件,对我们生成覆盖率没多大作用,我们把这两个从jar包里删除,在重新打包,这两个文件不存在了,也就不用签名了,问题就解决了。</p>    <h2>1.2 覆盖率包在部分4.X版本手机上生成ec文件失败</h2>    <p>事情起因:在测试新功能时,用打的覆盖率包,外包反馈部分4.X手机生成不了ec文件</p>    <p>问题重现:试了在自己的手机,华为mate8的6.0系统上生成正常,属于部分机型问题。</p>    <p>将问题手机借来后,生成ec文件提示失败。</p>    <p>问题排解:</p>    <p>查看logcat日志:</p>    <p><img src="https://simg.open-open.com/show/1b9991a80407fe2c9cc78cd7962e8e1e.png"></p>    <p>还有一段:</p>    <p>反射RT类的getAgent() 方法是提示</p>    <p><img src="https://simg.open-open.com/show/51fcc0fa14f828d3d4d2d2d40e7c879c.png"></p>    <p>(1)反射在其他手机是正常的,按道理不应该在部分问题手机会失败,但也做一下排查</p>    <p>报错的代码行:</p>    <p><img src="https://simg.open-open.com/show/7eaf067323f5cf47d270676335fc12a8.png"></p>    <p>网上有说InvocationTargetException问题可能是没有设置可见就访问私有</p>    <p>先看看RT的这个方法</p>    <p><img src="https://simg.open-open.com/show/4ebdbce0dd3f8ad5c351aac606a3cf21.png"></p>    <p>在看看Agent类的这个方法:</p>    <p><img src="https://simg.open-open.com/show/b84e035ba473c900c4a227979ec591b4.png"></p>    <p>尝试把私有字段可见,在去调用</p>    <p><img src="https://simg.open-open.com/show/e0e730f80d5e4bc1d60679f070a71e6a.png"></p>    <p>结果问题仍然存在,此种情况排除</p>    <p>(2)那我们就回到第一个错误, Class resolved by unexpected DEX</p>    <p>Agent出了两个地址。</p>    <p>我们在回过头来看应用宝的打包脚本,看看dex干了什么。</p>    <p>调用dex,输入classes,输出dex,下面对excludes里面的jar进行了排除</p>    <p>调用dex_sub,输入subclasses,输出second_dex,下面对excludes里面的jar进行了排除</p>    <p>回过头来在看看我们的插桩脚本,对dex、dex_sub这块只改了classes为classes_instr(用插桩后的打dex)</p>    <p>应用宝这个分包的逻辑,会分别打两个dex。</p>    <p>问题就找到了,因为没有改excludes部分,jacocoagent.jar是放在应用宝libs目录下的,默认dex和dex_sub都把jacocoagent.jar打了进去,运行时就会出现新的dex想要替换之前校验过的dex,也就出现agent有两个地址的缘故。</p>    <p>解决方法:</p>    <p>覆盖率打包的脚本,对dex_sub的excludes中加入jacocoagent.jar,这样两次dex只打一次jacocoagent.jar。</p>    <p>重新打包,ec文件正常生成。</p>    <h2>1.3 覆盖率报告生成后看不到源码覆盖情况</h2>    <p>源码和类文件都正确指定了,为什么生成的报告看不到源码覆盖?</p>    <p>解决方法:</p>    <p>(1)编译的时候debug=”true” 这个一定要设置,比如</p>    <p><img src="https://simg.open-open.com/show/e90bf8f5bbbafff75498111c4b1632e6.png"></p>    <p>(2)如果1没有错误,那就要看看你的源码和class文件路径指定正确没,JaCoCo是按照包名去搜索的,这个一定要确定好,很多项目会自建代码目录的。</p>    <h2>二、覆盖率一些需要注意的地方</h2>    <p>由于Android不能通过JVM停止后自动dump覆盖率数据,因此当Android应用进程不存在或停止的时候,覆盖率数据不会生成。</p>    <p>也就有了如下需要注意的地方</p>    <p>(1)没有启动应用进程,生成覆盖率数据会失败。</p>    <p>(2)覆盖率生成工具进程杀不杀掉,不影响覆盖率生成结果。</p>    <p>(3)测试过程中,杀掉应用进程,内存中的覆盖率数据会丢失。</p>    <p>(4)覆盖率数据是可以追加记录的,但最好在杀掉应用进程前先备份。</p>    <p>建议养成良好的操作习惯,定期生成覆盖率文件。</p>    <p>如果有杀掉应用进程的需求操作,请在操作前生成一次,这样之前的数据就有所保留了。</p>    <p>一次测试前,一定要保证先清理掉以前覆盖率的数据,否则以现有追加文件的方式的形式,会导致旧新的覆盖率柔和在一起,有可能merge时候会失败。</p>    <p> </p>    <p>来自:http://tmq.qq.com/2016/08/java-code-coverage-tools-jacoco-hit-the-pit/</p>    <p> </p>