基于JaCoCo的UT和IT覆盖率最佳实践

发表于:2018-4-28 17:58

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:于国庆    来源:OmniStack

  说起覆盖率,程序猿们的第一反应一定是代码的行覆盖率,这也正是本篇要讲的内容。但在这之前,我们还是简单聊聊关于覆盖率的二三事。
  关于覆盖率 
  广义上讲,覆盖率包括需求覆盖率和代码覆盖率。
  需求覆盖率这个概念可能很多人意识不到。然而实际工作中大量的争执都与其相关。
  关于需求覆盖率,思考这样一个问题:
  为什么100%的代码覆盖率不足以保证产品的质量?
  诚然,100%的代码覆盖率足以保证代码的质量。
  然而,却也仅能保证代码的质量,而非产品的质量。
  举个简单而极端点的例子,如果程序员完全误会了用户的需求,用户需要一把尺子,你却给他码了一双鞋,那么代码覆盖率再高,质量再完美也是徒劳,因为此时的需求覆盖率为0。
   那么,需求覆盖率的概念就显而易见了。
  简言之,即产品对用户的真实需求的覆盖率。
  而在实际工作中,产品经理和程序猿们的相爱相杀常在于此:
  这到底是一个新需求还是代码的bug?
  换句话说,这到底是产品经理的需求文档没有覆盖用户的需求,还是程序猿的代码没有覆盖产品经理的需求?
  1.2 代码覆盖率
  狭义上讲,我们通常所说的覆盖率指代码覆盖率,更狭义点讲,指的就是代码的行覆盖率。
  而事实上,代码覆盖率包含很多类:类覆盖率,函数覆盖率,分支覆盖率,行覆盖率等等。
  而接下来,我们将基于行覆盖率讲解JaCoCo在实际使用过程中的最佳实践。
  JaCoCo 
  2.1实时插桩和离线插桩
  关于JaCoCo原理的文章很多,不再赘述【1】。
   
  依据官网的建议,结合实际应用场景,本文采取更简单方便的实时插桩模式(on-the-fly)。
  另一种模式叫做离线插桩(offline instrumentation),相比实时插桩,其更广泛适用于以下场景【2】:
  1.运行环境不支持Java agent;
  2.部署环境不支持JVM参数;
  3.字节码需要转换格式以适配不同的虚拟机,例如Android Dalvik VM;
  4.与其他Java agent冲突。
  而在实际开发过程(Android应用开发除外)中,我们基本不会遇到以上情况,所以本文的最佳实践建议使用实时插桩模式。
  2.2 实时插桩原理
  JaCoCo Implementation Design图【3】
  
  JaCoCo实时插桩是基于JVM代理模式实现的。
  JVM代理程序可以在JVM加载Java Class时,动态修改Class的内容。JaCoCo使用了ASM库【4】来对Java Class,也就是字节码(byte code)做修改。
  JaCoCo代理程序工作原理图【5】: 
  启动Java程序时,使用java-agent参数指定JaCoCo代理程序。
  JVM启动时,会同时启动JaCoCo代理程序。
  当JVM通过Class Loader装载Class时,JaCoCo代理端会将统计代码(桩)实时插入Class,并在测试代码执行过程中统计分析覆盖率。   
  下图为反编译经过了插桩的Java Class的示例截图,其中var(var1[],var2[])数组即JaCoCo为统计代码覆盖率而插的桩:
  图2.3:JaCoCo插桩反编译代码示例
  3.使用JaCoCo统计UT/IT覆盖率最佳实践
  demo代码:
  https://github.com/flasheryu/jacoco-demo
  pom文件:
  https://github.com/flasheryu/jacoco-demo/blob/master/pom.xml
   
  最佳实践指导原则:
  UT覆盖率和IT覆盖率应分别统计并分别检查是否达到预定目标值X%。
  3.1使用JaCoCo Maven插件统计检查UT覆盖率
  POM文件简析:
  1.指定生成的覆盖率文件(jacoco-ut.exec)路径:
  图3.1:UT覆盖率文件路径
  2.单元测试使用surefire插件:
  图3.2:Maven Surefire插件
  覆盖率目标:
  依据POM文件配置,行覆盖率目标值为20%(仅供示例):
  图3.3:Maven JaCoCo插件UT检查步骤示例
  运行命令:
  mvn clean verify
  执行过程:
  首先,Maven构建test步骤生成jacoco-ut.exec;
  图3.4:UT覆盖率文件示例
  而后,在verify步骤,JaCoCo插件执行check goal检查代码覆盖率,并在违反规则时,使构建失败。
  执行结果示例:
  构建成功时:
  图3.5:UT测试成功结果示例
  构建失败时:
  图3.6:UT测试失败结果示例
  3.2. 使用JaCoCo Maven插件+SonarQube+Sonar-Break Maven插件统计检查IT覆盖率
  Sonar-Break插件:
  因原开源插件不兼容最新版本SonarQube的API,本文中所使用的sonar-breakMaven插件,是基于原插件更新而来。
  原项目地址:https://github.com/sgoertzen/sonar-break-maven-plugin
  最新兼容版地址:https://github.com/flasheryu/sonar-break-maven-plugin
  POM文件简析:
  1.指定生成的覆盖率文件(jacoco-it.exec)路径:
  图3.7:IT覆盖率文件路径
  2.指定上传到SonarQube做分析的覆盖率文件路径:
  图3.8:SonaQube检查IT覆盖率文件路径
  3.集成测试使用的failsafe插件和检查SonarQube执行结果的sonar-break插件:
  图3.9:Maven Failsafe插件

  图3.10:Maven Sonar-Break插件
  覆盖率目标:
  参考SonarQube上Quality Gate配置,覆盖率低于50%警告,低于35%则报错:
  图3.11:SonarQube Quality Gate配置示例
  运行命令:
  mvn clean verify sonar:sonar
  mvn sonar-break:sonar-break
  执行过程:
  首先,Maven构建在integration-test时生成jacoco-it.exec:
  图3.12:IT覆盖率文件示例
  而后,在sonar:sonar步骤,SonarQube对代码做静态分析,并在SonarQube首页给出结果:
  SonarQube测试通过时:
  图3.13:SonarQube IT测试成功结果示例
  SonarQube测试警告时:
  图3.14:SonarQube IT测试警告结果示例
  SonarQube测试失败时:
   图3.15:SonarQube IT测试失败结果示例
  最后,在sonar-break:sonar-break步骤,拉取SonarQube测试结果,并依据此结果(包含测试覆盖率)做出最终判定。如若测试结果失败,则使构建失败。
  执行结果示例:
  构建成功时:
   图3.16:Maven IT测试成功结果示例
  构建成功但有警告时:
   图3.17:Maven IT测试警告结果示例
  构建失败时:
   图3.18:Maven IT测试失败结果示例
  4.最佳实践总结
  回到最初的最佳实践指导原则:
  UT覆盖率和IT覆盖率分别统计并分别达到预定目标值X%。   
  本文中设置的UT覆盖率阈值为20%,IT为35%(仅供示例)。
  若要使项目通过CICD管道检查,必须同时满足UT覆盖率>20%和IT覆盖率>35%两个条件,否则构建失败。   
  而不推荐的实践则是:
  仅给出一个覆盖率阈值,并统计检查UT+IT合计达到的覆盖率是否超过此值。
  理由很简单:
  1.基于TDD和CICD最佳实践,代码应通过本地UT测试以及覆盖率检查,方可提交到主代码库,因此须单独规定UT覆盖率;
  2.基于同样的原则, 代码提交到代码库后,执行集成测试,并在此时检查IT覆盖率,因此须单独规定IT覆盖率。
  结论为,当使用JaCoCo统计检查UT和IT行覆盖率时,建议的最佳实践为:
  使用JaCoCo Maven插件统计检查UT覆盖率,使用JaCoCo+SonarQube+Sonar-Break插件统计检查IT覆盖率。


上文内容不用于商业目的,如涉及知识产权问题,请权利人联系博为峰小编(021-64471599-8017),我们将立即处理。

《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号