一、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. go语言游戏服务端开发(一)——架构

    五邑隐侠,本名关健昌,12年游戏生涯. 本教程以Go语言为例.   网络游戏程序分为客户端和服务端.客户端负责图形渲染.交互和一些简单校验处理,服务端负责业务逻辑处理.数据存储. 我们开发一个游戏de ...

  2. pibbtimq高级使用技术,双向通信

    本案例目是是服务端发送客户端,客户端收到反应给服务端,双向通信客户端代码如下:import pikaimport timeconnection = pika.BlockingConnection(pi ...

  3. 彻底搞明白PHP的中引用的概念

    之前我们其实已经有过几篇文章讲过引用方面的问题,这次我们来全面的梳理一下引用在PHP到底是怎么回事,它和C中的指针有什么不同,在使用的时候要注意些什么. 什么是引用? 在 PHP 中引用意味着用不同的 ...

  4. http请求在https中使用

    问题原因:HTTPS页面里动态的引入HTTP资源,比如引入一个js文件,会被直接block掉的.在HTTPS页面里通过AJAX的方式请求HTTP资源,也会被直接block掉的. 解决方案: <m ...

  5. PHPMailer实现发送邮件的方法介绍

    来自: https://www.php.cn/php-weizijiaocheng-408762.html PHPmailer请在github下载,或者直接百度,也不难,虽然PHPmailer里面一大 ...

  6. Java基础系列(15)- 用户交互Scanner

    Scanner对象 之前我们学的基本语法中我们并没有实现程序和人的交互,但是Java给我们提供了这样一个工具类,我们可以获取用户的输入.java.util.Scanner是Java5的新特征.我们可以 ...

  7. Linux系列(21) - 光盘、U盘挂载

    挂载光盘 mount命令.umount命令 step-1 建立挂载点 原理:相当于建立盘符,建个目录读取光盘内容 命令:[root@localhost ~]# mkdir /mnt/cdrom/ 备注 ...

  8. 使用 FIO 对 Kubernetes 持久卷进行 Benchmark:读/写(IOPS)、带宽(MB/s)和延迟

    工具 Dbench https://github.com/leeliu/dbench 用法 编辑 dbench.yaml 文件中的 storageClassName 以匹配你自己的 Storage C ...

  9. 看完小白也会使用,Android投屏神器scrcpy详细教程

    楔子 做为一个软件测试工程师,在使用手机测试的时候,缺陷附件想附上截图.视频,需要从手机把图片.视频发送到拷贝或发送到电脑,非常麻烦. 所以想到使用投屏软件,把手机的屏幕投屏到电脑,便可以直接在电脑上 ...

  10. jquery 设置django全局token

    通过JQUEYR中的ajaxSetup,来设置django中的token,即不需要再每次都去引用: 第一步: 先django中的html中设置 {%  csrf_token %} 第二步: 新一个js ...