一、JaCoCo简介

JaCoCo是Eclipse平台下的开源产品,以小型,轻量化著称,常见集成在Eclipse Workbench中,除此之外的启动方式包括对接Ant和Maven,或是命令行的方式进行。Jacoco近两年在软件测试行业的被关注度比较高,其主要原因是:在新一代精准测试技术流的影响中,各大型单位对覆盖率的追求越来越迫切。作为一款开源产品,它主机面向Java语言,能够在字节码层面给出覆盖率,同时也能将字节码关联到对应的源代码。这种半精准的测试方式,在小型团队中,对于某些场景的覆盖率诉求,起到了一定的响应。但它也有很强的局限性,尤其在支撑大型系统应用中,其表现能力弱,准确率不够达标。这是它致命的缺点,也为它在大型系统中应用的 失败埋下了伏笔。如何下此结论?本文作者将从应用者的角度,并参照国外用户的总结文献做一综合分析罗列。因本人的学识所限,归纳的肯定不够全面,如有不准确之处,还请同行拍砖、指正。

二、JaCoCo的技术内核

JaCoCo覆盖率的采集,主要是通过插装及装点的执行来收集程序运行的特征数据。JaCoCo的插装,是通过agent在字节码中插入boolean[]数组,来标记每句可执行代码,只要执行过相应语句,boolean[]数组会产生相应标记(True or False),这个boolean数组连同产生的标记称之为探针(Probe)。

当源码被编译为字节码时,源码的逻辑指令,例如条件判定,循环等,会被编译为特殊指令,JaCoCo在动态插装的过程中,当处理到这些指令时,会根据不同的逻辑进行不同的插装方式。

图表 1 Java源代码(左)和对应字节码 (右)

图1中IFEQ和G0T0都是JUMP(跳转)指令,通过JUMP指令直接能从一个节点,跳转到另一个节点。针对JUMP指令的插装方式,有多种选择。有些是在指令前插入探针,有些是在指令后插入探针(见表格1)。类似的,在面对其他特殊指令时,例如ENTRY(程序启动), SEQUENCE(序列执行),或者EXIT(程序终止)等,均有不同的插装操作。图2以面对JUMP类型指令的插装作为示例,其中左图为未插装的字节码,右图为装点位置的示意图。

图表 2针对JUMP类型指令的插装示意

表格 1面对不同类型指令的插装方式

JaCoCo的这种插装方式,特别需要指出的是:

  • 看似针对不同类型的指令,通过不同的插装方式,反映了不同的逻辑关系,但由于其对整体的结构没有把控,当程序较为复杂时,十分容易产生误差,并且难以反映真实的调用关系。
  • 除了表1列出的几种指令外,JaCoCo对于其他的指令视为Exception,并不予处理,整个插装过程,以及插装位置对于用户而言均不可见,无法通过人工干预合理和调整插装问题,导致即使用户有排查问题的需求和能力,也无从有效研究问题的根源。
  • 这种无序的混乱插装方式,也造成不必要的性能开销,比如:使用JaCoCo会使代码的膨胀率增加约30%,并增加约10%的性能消耗。(由于JaCoCo的设计初衷是针对民用项目,因此优化程度较低,当项目规模较小时,其影响并不显著,但是对于资源十分宝贵的商业项目,会产生较大的负荷。)

三、JaCoCo的覆盖率实现

比较常见的覆盖率标准,按粒度从粗到细依次是:语句覆盖,分支覆盖,条件覆盖,路径覆盖。JaCoCo可以实现语句覆盖,以及部分情况下的分支覆盖。一些研究表明,JaCoCo在分支覆盖层级,对结构控制只研究了if-else的情况,因此该层级的评估无法保证所有可执行语句的正确执行[1]。同时,JaCoCo所谓支持的条件覆盖结果其实不适合商用,由于字节码和源码之间的信息差,它只能衡量条件真假是否覆盖的比率,但无法有效确定某个具体条件执行的精确结果。而在企业级应用场景下,实现精确的条件覆盖是刚性需求,JaCoCo因为没有代码静态分析辅助永远无法纯粹通过字节码获取精确的条件和分支覆盖。

因此,JaCoCo优点是,可以进行粗粒度的覆盖率度量,比较适用于对于项目的整体初步评估。

在真正的精准测试的体系中,对于覆盖率的计算和展示,其实现基础是测试信息到源码,再从源码到测试用例的精准关联和信息映射。与其相比,Jacoco最大的弱点是:易产生覆盖率的计算偏差。

  • JaCoCo原生不支持和测试用例的关联。因此只能在手动执行测试用例后,给出当前测试用例所对应的整体覆盖率信息。受限于设计理念,JaCoCo的覆盖率是在字节码层级统计,为了用户的可读性和可研究性,需要和源码进行关联,关联的过程通过一种映射机制(mapping)来实现,而在这种映射的过程中,会损失大量的信息,因此,会进一步造成覆盖率信息的误差。
  • 在覆盖率的应用端,商业适配性较差。第一,JaCoCo不支持多项目并行或者多版本累计的覆盖率统计,其覆盖率只针对某个用例对于某个项目的评估。JaCoCo的理念更偏向于传统白盒测试工具,在敏捷迭代的场景下,JaCoCo无法对版本/轮次/里程碑版本/项目之间的差异或者总体覆盖率计算进行支持。第二,JaCoCo原生不支持真正意义上的精准测试,其内部数据表达都是聚合的数组,不支持区分不同线程的覆盖率统计。第三,JaCoCo不支持实时的覆盖率展示,其覆盖率结果只能在该测试任务结束后生成。第四,JaCoCo不支持结果的自动保存和累计,一旦退出环境,所有未经保存的结果都会被清空。
  • 对于程序的逻辑结构和调用关系,JaCoCo除了在动态插装的过程中进行实时分析以外,并无其他的获取方式。而对于覆盖率的JaCoCo能够在Java文件的基础结构层级的基础上,从四类数据:覆盖率,被覆盖行数,未覆盖行数,以及总行数,实现覆盖程度的评估和展示。其界面如图3所示。同时,在实现源码和字节码的映射后,统计的覆盖率信息也会相应的在源码端的代码行上进行展示,界面如图4所示,其中绿色代表完全覆盖,黄色代表部分覆盖(一些指令或者分支未覆盖),红色代表未覆盖,这些颜色也支持用户自定义。针对覆盖结果的导出,JaCoCo支持HTML,XML,CSV等文件格式,用户也可以在Eclipse内进行查看。

图表 3 JaCoCo覆盖率展示界面

图表 4 JaCoCo在源码端的覆盖率展示

四、应用局限性

JaCoCo天生缺陷的内核设计和定位,带来了应用的局限。作为一款热门开源工具,虽然被爱好者们在小范围及初步信息判断中使用较多,但是却因为大量的误差,不能被应用更大、更复杂的大型核心系统上,否则用户可能将面临着很大的技术风险。

覆盖率误差:JaCoCo的插装过程具有一定的技术局限性,其装点并非明文可见,存在大量的信息差。发表在IEEE上的文章:“Negative effects of bytecode instrumentation on Java source code coverage”,对JaCoCo的误差情况以及可能原因进行了详尽的评估与分析[2]。

JaCoCo与标准基线对比结果显示:针对不同的项目,在类(Method)层级,JaCoCo的覆盖率评估就已产生了0.2%-8.5%左右的绝对误差和0.7%-23.859%的相对误差。在更细化的语句行和分支层级,其误差将会被指数级放大。

表格 2 JaCoCo覆盖率评估的相对误差[2]

误差产生的具体成因:

  • 复杂系统通常由大量子模块组成,JaCoCo无法实现对于内部被调用的子模块进行插装,因此对于子模块覆盖率的评估会产生显著的误差。
  • 如果某个子模块没有被调用,那么对于JaCoCo来说,该模块内的方法等同于不存在。JaCoCo需要调用该子模块,才能将该子模块内的代码计入覆盖率计算的“分母”。
  • 除了几种既定的逻辑意外事件,JaCoCo无法正确处理例外情况(Exception),如果在控制流程中遇到Exception,JaCoCo会把这种情况直接标记为未覆盖,这种判定方式直接的影响到了对程序逻辑关系的把控,造成对于覆盖率无法准确评估。

误差引发的后果:

  • 伪瓶颈的产生,以及对测试质量的错误高估。第一种情况,测试人员投入大量工作之后,却无法进一步提升覆盖率,造成对资源和实践的浪费;第二种情况,会让用户误将未达标的系统判定为达标,有可能引发严重的生产事故。
  • 无法实现缺陷定位,大量的算法和应用依托覆盖率的输入,而缺陷定位更是其中最主要的实践。
  • 回归测试的精准度,受到了严重的影响。

五、对接能力分析

JaCoCo对于Ant和Maven有较完整的插件支持启动方案,但是只能和Eclipse或者SonarCube集成,无法实现和测试管理软件,或是上下游测试工具的完整对接。

对于开发流程,JaCoCo依然是传统白盒测试的思维,即瀑布式的开发模式,需要在代码更新后重新进行测试,每次版本迭代的工作量都十分庞大。

自动化层面,JaCoCo支持与Jenkins的对接。

六、结语

JaCoCo能够有效的在字节码层级提供覆盖率的初步评估和计算,并且有实现从字节码关联到源码的能力。但是,JaCoCo只是一款提供粗略评估工具,无法自动关联用例、无法有效提升测试效率,没有作为测试中台的对接和支持能力。JaCoCo的定位和实践,表明其更适用于偏向辅助个人开发者和小型项目组对项目覆盖率进行非常基础的评估,对于支撑大型企业级应用的精准测试需求,依然路途漫长。

参考文献:

[1]      N. Li, X. Meng, J. Offutt, and L. Deng, “Is bytecode instrumentation as good as source code instrumentation: An empirical study with industrial tools (Experience Report),” 2013 IEEE 24th Int. Symp. Softw. Reliab. Eng. ISSRE 2013, pp. 380–389, 2013, doi: 10.1109/ISSRE.2013.6698891.

[2]      D. Tengeri, F. Horváth, Á. Beszédes, T. Gergely, and T. Gyimóthy, “Negative effects of bytecode instrumentation on Java source code coverage,” 2016 IEEE 23rd Int. Conf. Softw. Anal. Evol. Reengineering, SANER 2016, vol. 1, pp. 225–235, 2016, doi: 10.1109/SANER.2016.61.

 

精准测试系列分享之一:JaCoCo 企业级应用的优缺点分析的更多相关文章

  1. 精准测试与开源工具Jacoco的覆盖率能力大PK

    导读:本文根据实际使用情况,简要分析了精准测试和类Jacoco等传统白盒工具在设计理念.功能和应用场景的异同点,并阐述了覆盖率技术如何在新型企业开发体系中,发挥应有的重要作用. 覆盖率技术可以说是测试 ...

  2. 精准测试白皮书v3.0-2019最新版

    现代社会是建立在各种以计算机为基石的软件技术基础之上的.随着日新月异的需求变化,软件系统越来越复杂.很多人觉得软件开发才是重要环节,但实际上,无法对大型软件进行有效的质量把控,就无法真正构建与维护大型 ...

  3. 《Linux命令学习手册》系列分享专栏

    <Linux命令学习手册>系列分享专栏 <Linux命令学习手册>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/read/207 ...

  4. 《Nginx高性能Web服务器》系列分享专栏

    <Nginx高性能Web服务器>系列分享专栏 [作者:Poechant] Nginx是目前最流行的基于BSD-like协议.轻量级.高性能的HTTP服务器.反向代理服务器和电子邮件(SMT ...

  5. 《AngularJS学习整理》系列分享专栏

    <AngularJS学习整理>系列分享专栏   <AngularJS学习整理>已整理成PDF文档,点击可直接下载至本地查阅https://www.webfalse.com/re ...

  6. 【数量技术宅|量化投资策略系列分享】股指期货IF分钟波动率统计策略

    更多精彩内容,欢迎关注公众号:数量技术宅.想要获取完整策略代码,请加技术宅微信:sljsz01 股指期货分钟级别波动率观察 在A股市场,股指期货是由一揽子股票组成的股票现货指数,所对应的期货.由于期货 ...

  7. 【数量技术宅|金融数据分析系列分享】为什么中证500(IC)是最适合长期做多的指数

    更多精彩内容,欢迎关注公众号:数量技术宅.探讨数据分析.量化投资问题,请加技术宅微信:sljsz01 投资股票指数相比个股的优势 我们在投资股票的时候,如果持仓集中在一只或者有限几只股票上,恰好不幸遇 ...

  8. 《Linux基础知识及命令》系列分享专栏

    <Linux基础知识及命令>系列分享专栏 本专题详细为大家讲解了Linux入门基础知识,思路清晰,简单易懂.本专题非常适合刚刚学习Linux的小白来学习,通过学习该专题会让你由入门达到中级 ...

  9. 【星云测试】Devops微服务架构下具有代码级穿透能力的精准测试

    微服务是Devops场景下热门的开发框架,在大型项目中被广泛采用.它把一个大型的单个应用程序和服务拆分为数十个的支持微服务,独立部署.互相隔离,通过扩展组件来处理功能瓶颈问题,比传统的应用程序更能有效 ...

随机推荐

  1. Xshell 为什么会出现中文乱码?

    在网上下载xshell并成功安装了,但是当登录服务器查看中文时却出现了乱码的现象呢?这是怎么回事呢?本集小编就同大家详细讲讲. 图1:使用中文命名文档 现象: 登录服务器查看中文却出现乱码 原因分析: ...

  2. HDU - 2544最短路 (dijkstra算法)

    HDU - 2544最短路 Description 在每年的校赛里,所有进入决赛的同学都会获得一件很漂亮的t-shirt.但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候,却是非常累的!所以 ...

  3. UVA 1599 Ideal Path(双向bfs+字典序+非简单图的最短路+队列判重)

    https://vjudge.net/problem/UVA-1599 给一个n个点m条边(2<=n<=100000,1<=m<=200000)的无向图,每条边上都涂有一种颜色 ...

  4. gentoo(贱兔) Linux作业系统的基本使用

    emerge是gentoo linux的portage包管理器的命令行工具emerge的基础使用:emerge 软件包名:安装某软件包 emerge nanoemerge --ask 软件包名:交互式 ...

  5. 一文让你彻底理解SQL关联子查询

    员工表的主要信息: 需求:检索工资大于同职位的平均工资的员工信息. 直觉的做法 员工多,而相应的职位(如销售员.经理.部门经理等)少,因此首先想到的思路是对职位分组,这样就能分别得到各个职位的平均工资 ...

  6. WPF进阶技巧和实战01-小技巧

    Svg在WPF中的使用 方法1:拷贝svg中的部分代码转换成Geometry(作为Path的Data使用) 在vs或者直接打开svg,看到如下代码: <?xml version="1. ...

  7. C++ 多线程按顺序执行函数

    我们提供了一个类: public class Foo { public void first() { print("first"); } public void second() ...

  8. Jetbrains CLion 安装与激活 详解

    1. 下载与安装 1.1 下载 这里提供了三个操作系统的官网下载地址 Mac Windows Linux 进入页面后向下拉点击蓝色按钮即可下载. 1.2 安装 这里将用 MacOS 来进行示例,Win ...

  9. oracle 不能用上下键调用sql语句

    在Linux的sqlplus中运行SQL语句之后,想用上下键把历史命令找出来,发现不支持. 安装rlwrap 重启sqlplus 3,使用rlwrap,rlwrap sqlplus / as sysd ...

  10. 如何基于Jupyter notebook搭建Spark集群开发环境

    摘要:本文介绍如何基于Jupyter notebook搭建Spark集群开发环境. 本文分享自华为云社区<基于Jupyter Notebook 搭建Spark集群开发环境>,作者:apr鹏 ...