Lombok 由于其使用的便利性, 目前流传非常广泛。甚至有呼声希望其能被Java官方引入,成为JDK的一部分。
当然凡事都有两面性,Lombok的引入也是有代价的。一时注释一时爽,结果导致代码在不知不觉中翻了好几倍。
例如以下几个简单的注解,背后是N多个自动生成的方法,
这其中尤其是@Data这个注解,会附带相当多的方法。
默认情况下,由于Jacoco不会区分Lombok生成的代码和正常的源代码。结果,在引入Lombok后就会发现,覆盖率通常会低得让人匪夷所思。例如某个项目,通过Jacoco获取到的代码行数以及覆盖率为:
可见,这个覆盖率是非常低的,会被质量门禁判违规(常见会要求>50%甚至>80%)。
这种情况下,开发者一般会有两个选择:
通常这两个方案都是不可取的。
专门为这些生成的代码编写用例是没有意义的。既然使用了Lombok,一个默认的前提就是Lombok是正确可靠的,为这些自动生成的代码进行单元测试不是一件高优先级的事情,还是放过已经996的码农和他们的头发吧,要爱护那些愿意写单元测试的好同志。
第二种方案也不可取,这会引入一个非常不好的开始,因为破窗效应,马上质量门禁也没有意义了。千万个教训告诉我们,千万不要去考验人性。
两种选择都没有意义,也都不可取,于是马上就有人想到了第三种方法
3 手工排除Bean
无论是Jacoco还是Sonar,都提供了exclude的方式,通过配置项来指定统计时排除某些特定的包或者类。如对于Jacoco可以在jacoco-maven-plugin的<configuration>中有如下配置,用于排除指定的内容。
<configuration>
<excludes>
<exclude>**/*DTO.*</exclude>
<exclude>**/domain/**/*</exclude>
</excludes>
</configuration>
第一个<exclude>标签将吧所有DTO结尾的类排除,而第二个<exclude>标签将把domain目录和子目录下的所有类都排除出去。
通过这个方式,也可以在数据源头上进行排除。
类似的,还可以通过基于jacoco覆盖率报告来自研解析工具,进行覆盖率或者增量覆盖率计算。这个过程中,也可以指定需要排除的包或者类,实现类似的做法。
当然,这种方式也需要项目有一些项目结构和命名上的约定,以保证过滤的正确。另外,既然放开了过滤的条件,有可能会让人钻空子。
4 使用Sonarqube 而不是Jacoco的结果
虽然Jacoco中的数据受到了lombok的污染,但是SonarQube由于有自身代码行的计算是根据扫描的源码,再根据自身的算法进行计算,并不是根据Jacoco提供的数据。再由此计算覆盖率的时候,就可以部分规避掉这个问题了。所以这是一个正解。当然,由于SonarQube和Jacoco的代码行、覆盖率等算法有差异,最好是保持指标数据源前后的一致性,避免混用。
5 使用lombok.addLombokGeneratedAnnotation
其实从Jacoco 0.8.0开始,其实就具备了可以将lobmok生成的代码从Jacoco报告中排除的能力。发布说明可以参见
https://github.com/jacoco/jacoco/pull/513
具体做法是,在项目的根目录下新建一个名字为lombok.config的文件,里面有如下的内容,
config.stopBubbling = true
lombok.addLombokGeneratedAnnotation = true
Lombok在为由其生成的构造方法、方法、字段和类型中增加@Generated注解,然后Jacoco借助这个注解来实现更为准去的排除。排除以后的结果如下,
当然,这个方案对两者的版本也有限制,要求Lombok >= 1.16.14, jacoco>0.8.0
本文案例图片来自: rainerhahnekamp ,案例源码可以从 GitHub 上获取。
总结一下,面对lombok,有如下五种解决方案,推荐后两种哦。
1专门为这些生成的代码编写单元测试用例 【X】
2要求降低质量门禁中的覆盖率要求【X】
3手工排除Bean 【X】
4使用Sonarqube 而不是Jacoco的结果【OK】
5使用lombok.addLombokGeneratedAnnotation 【OK】
覆盖率统计,我们是认真的