简记代码覆盖率工具jacoco(Java Code Coverage)在android项目中的实践。
app目录里面的build.gradle
文件:
1 | apply plugin: 'jacoco' |
AndroidManifest.xml
:
1 | <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> |
启动第一个activity:
1 |
|
第一个activity,可以在AndroidManifest.xml
中查找android.intent.action.MAIN
得到,也可以启动app时由adb logcat | grep ActivityManager
得到。
按机身back键退出app时必经的activiy:
1 |
|
点back键退出时检查日志,看onDestroy()方法是否被调用了。out = new FileOutputStream("/mnt/sdcard/coverage.ec", true);
写成true即追加而不是覆盖。
一般实际项目中,这些activity通常会继承一个上层activity(一些通用方法的封装), onCreate()和onDestroy()中增加的coverage相关方法也可以写在这个父activity类中。
执行完测试后,adb pull /mnt/sdcard/coverage.ec到app/build/outputs里面(该目录在task jacocoTestReport配置),然后项目根目录下运行./gradlew jacocoTestReport
,最后在app/build/reports中查看报告即可。
错误解决
错误1:
执行./gradlew jacocoTestReport
报错:
[jacoco:report] Classes in bundle ‘Code Coverage Report’ do no match with execution data. For report generation the same class files must be used as at runtime.
[jacoco:report] Execution data for class xxxxx does not match.
[jacoco:report] Execution data for class yyyyy does not match.
原因,编译apk的Java版本和生成Jacoco报告的Java版本不一致(都是Java8,但小版本不一致)。android studio默认的JDK不是电脑系统的而是自带的/Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin
。(在项目上右键Open Module Settings
可以看到)这里有两篇文章解释的比较详细:文章一,文章二。
错误2:
有时候遇到其它莫名错误,可以用Android Studio的Build - Project Clean
一下,或者Invalidated Caches / Restart...
。
错误3:./gradlew jacocoTestReport
生成报告时:
Caused by: java.lang.IllegalStateException: Can’t add different class with same name:
存在同名class,(intermediates/classes
下有debug和release两个文件夹),删除release文件夹或者classDirectories写到debug,${project.buildDir}/intermediates/classes/debug
。
报告合并
多个.ec
文件直接扔到app/build/outputs
文件夹中(该目录在task jacocoTestReport配置)即可,会自动合并报告。
自动插桩
可以把变更打成svn patch,
1 | svn diff > ../coverage.patch |
svn 重新拉取代码后,导入 patch
1 | svn patch ../coverage.patch |
git也一样,命令略有差异。
todo
1,做server,可以接收文件,手机端退出时自动把ec报告发送至server。
2,2017年GITC全球互联网技术大会上,听了饿了么邱化峰的报告,他们代码覆盖率做得比较深入(以下摘自邱化峰ppt):
- 最少用例数
覆盖所有情况使用的最少用例数,在系统软件和军事软 件有75%的在使用,将圈复杂度维持在10以下有很多实 际的和经济的理由,低于10的软件是非常简单且很容易 跟踪的, - 圈复杂度-降低圈复杂度的重构技术
代码复杂度的衡量标准,程序的可能错误和高的圈复杂度有着很大关系,圈复杂度可以成为编码及重构的重要参考指标。参考 《代码大全》 《重构 改善既有代码的设计》。- 提取函数— 将独立业务活模块代码单独封装为函数
- 算法替换—复杂的算法可能会导致Bug,满足功能的前提下,使用简单的算法
- 解条件式—复杂的条件表达式封装为函数
- 合并条件式—将一系列得到相同结果的条件表达式合并
- 查询函数和修改函数分离—-单一职责原则,强调复用性
- 合并重复的条件判断——不同的分支有相同的处理,提炼到分之外
- 跟CI的持续集成
- 1.自动化的回归并收集代码覆盖率
- 2.查看代码覆盖率的历史记录
- 精准的代码覆盖率
- 1.识别出所有被修改的方法(新增,删除和修改)
- 2.可以有效的查看那些被修改的方法是否被测试到
- 3.通过圈复杂度衡量代码的质量
- 突变测试