以Apache Ignite为例评估Java项目的测试覆盖率

我参与了开源Apache Ignite项目的开发,而在从事该项目时,评估测试覆盖范围对我来说变得很有趣,这就是结果。



测试覆盖率是用于评估产品测试质量的最流行指标。


这是使您能够识别由于遗漏错误风险而需要引起注意的区域并确定模块或项目组件的工作优先级的少数度量标准之一。


获得有关评估Java项目测试覆盖率的完整报告的最简单方法是使用IntelliJ IDEA中内置的coverage 跟踪器 。 它使您可以单击几次来配置一组指标,并在随后的报告生成中运行测试。


在Apache Ignite项目中进行测试


Apache Ignite项目使用其自己的测试框架进行测试,该框架基于JUnit 3实施。在撰写本文时,核心项目模块包含约82,000个测试,其中大多数是组件测试,并且需要从多个节点(包括不同的JVM)中构建一个集群。同时准备环境。


值得注意的是,确保如此庞大的回归基础的可操作性并非易事。 社区不断监视产品的状态,并纠正作为“ 使团队再次成为绿色”计划的一部分而发现的错误。


出于以下原因,指示的项目功能不允许在一个JVM中一次运行所有测试:


  • 可能的错误OutOfMemoryError;
  • JVM可能崩溃;
  • 可能的僵局;
  • 由于先前测试中节点未停止,因此无法启动测试;
  • 在一台计算机上,运行需要三天。

所有这些使得不可能使用IntelliJ IDEA来获得项目所有测试的报告,并且需要一种特殊的方法来解决问题。


准备并进行测试覆盖率评估


根据所做的工作,选择了最可靠的方法来完成任务,其中包含以下步骤:


  1. 定义一组测试类;
  2. 每个测试类别的执行:
    2.1。 使用监视程序计时器在单独的JVM中启动和运行一组类测试,该监视程序计时器将在发生冻结或测试问题时终止线程;
    2.2。 获取和保存测试覆盖率指标的操作;
    2.3。 完成测试后清洁环境;
  3. 合并第2段中获得的所有指标;
  4. 完整的报告生成。

有许多评估测试覆盖率的工具,其中最受欢迎的是:



我不会详细介绍它们之间的差异; 此处提供一个可视化表格,用于比较评估测试覆盖率的工具的功能。


为了解决该问题,选择了JaCoCo库,以便能够将解决方案嵌入TeamCity ,而Apache Ignite项目的现有测试基础结构正是基于TeamCity的。 TeamCity可以与JaCoCo一起使用


为了自动化描述的算法,使用了bash脚本和MavenJacoco Maven插件的配置由pom.xml中的单独Maven配置文件实现。


JaCoCo插件的配置文件如下所示,它意味着分为两个单独的开始:


  1. 在连接了JaCoCo代理( prepare-agent )的情况下运行测试,以收集测试覆盖率指标。 “ runDirectory”属性将在启动时由脚本传递,这将允许单独保存运行结果;
  2. 合并运行结果( merge )和报告生成( report )。

Maven JaCoCo配置
<profile> <id>coverage</id> <properties> <argLine> -ea \ -server \ -Xms1g \ -Xmx6g \ -XX:+HeapDumpOnOutOfMemoryError \ -XX:+AggressiveOpts \ -DIGNITE_UPDATE_NOTIFIER=false \ -DIGNITE_NO_DISCO_ORDER=true \ -DIGNITE_PERFORMANCE_SUGGESTIONS_DISABLED=true \ -DIGNITE_QUIET=false \ -Djava.net.preferIPv4Stack=true \ </argLine> <coverage.dataFile>${runDirectory}/coverage-reports/jacoco-ut.exec</coverage.dataFile> <coverage.outputDir>${runDirectory}/jacoco-ut</coverage.outputDir> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> </configuration> <executions> <execution> <id>default-test</id> <phase>test</phase> <goals> <goal>test</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.1</version> <executions> <execution> <id>default-prepare-agent</id> <goals> <goal>prepare-agent</goal> </goals> <configuration> <destFile>${coverage.dataFile}</destFile> </configuration> </execution> <execution> <id>post-merge</id> <phase>validate</phase> <goals> <goal>merge</goal> </goals> <configuration> <fileSets> <fileSet> <directory>${basedir}</directory> <includes> <include>results/*/coverage-reports/jacoco-ut.exec</include> </includes> </fileSet> </fileSets> <destFile>merged.exe</destFile> </configuration> </execution> <execution> <id>generate-report</id> <phase>validate</phase> <goals> <goal>report</goal> </goals> <configuration> <dataFile>${basedir}/merged.exe</dataFile> <outputDirectory>${basedir}/coverage-report</outputDirectory> </configuration> </execution> </executions> </plugin> </plugins> </build> </profile> 

下面是一个脚本,实现了前面描述的步骤。


控制bash脚本
 #!/bin/bash #        DEVNOTES.txt # #    : ignite/modules/core # #   : 'nohup ./coverage.sh >/dev/null 2>&1 &' SCRIPT_DIR=$(cd $(dirname "$0"); pwd) echo "***** ." echo "*****   ..." tests=() while IFS= read -r -d $'\0'; do tests+=("$REPLY") done < <(find $SCRIPT_DIR/src/test/java/org/apache/ignite -type f -name "*Test*" ! -name "*\$*" ! -name "*Abstract*" ! -name "*TestSuite*" -print0) testsCount=${#tests[@]} echo "*****   ="$testsCount idx=0 for path in ${tests[@]} do idx=$((idx+1)) echo "*****  "$idx"  "$testsCount echo "*****  : "$path filename=$(basename -- "$path") filename="${filename%.*}" echo "*****  : "$filename runDir=$SCRIPT_DIR"/results/"$filename mkdir -p $runDir if [ "$(ls -A $runDir)" ]; then continue fi echo "*****  ..." timeout 30m mvn -P surefire-fork-count-1,coverage test -Dmaven.main.skip=true -Dmaven.test.failure.ignore=true -Dtest=$filename -DfailIFNoTests=false -DrunDirectory=$runDir echo "*****  ..." pkill java done #      mvn -X -P surefire-fork-count-1,coverage validate echo "***** ." 

在专用服务器上运行所有进行覆盖评估的测试大约需要50个小时:4个vCPU,8RAM,50个SSD, Ubuntu x64 16.04


如果有可用资源,可以很容易地将所描述的方法并行化到多个机架,这将大大减少运行时间并评估测试范围。 在将此解决方案嵌入TeamCity后 ,测试覆盖率评估时间应大约需要2个小时。


结果


根据报告的结果,项目说明覆盖率约为61%。


主要组成部分的说明范围:


  • 快取-66%
  • 发现-57%
  • 计算-60%
  • 流-51%
  • 二进制-68%
  • 交易-71%

对结果进行分析后,很明显,所有热门代码以及用于解决典型问题的代码均已覆盖。 有了这样的工具包,将有可能将覆盖范围扩展到罕见和非典型情况,从而使产品更加可靠。


PS 完整报告修订

Source: https://habr.com/ru/post/zh-CN413587/


All Articles