我想使用
jacoco maven plugin
在构建过程中使用 'check'
目标检查最低级别的代码覆盖率。
对于单模块项目,一切正常。 但对于多模块,我想检查所有模块的代码覆盖率的平均水平,但
check
目标分别检查每个模块。
例如,module1 的代码覆盖率为 70%,module2 的代码覆盖率为 100%,两个模块中所有行的平均代码覆盖率为 85%。 我尝试将所有项目的代码覆盖率设置为 80%,但由于第一个模块而失败。
来自 pom:
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.7.6.201602180812</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<phase>prepare-package</phase>
<goals>
<goal>report</goal>
</goals>
</execution>
<execution>
<id>default-check</id>
<goals>
<goal>check</goal>
</goals>
<configuration>
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>COMPLEXITY</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
</rules>
</configuration>
</execution>
</executions>
</plugin>
简短的回答:(在撰写本文时)仅使用 Maven 和 Jacoco 是不可能的。
当前的 JaCoCo Maven 目标仅适用于单个模块:测试在模块内执行,并且仅对同一模块内的代码提供覆盖范围。覆盖率报告是为每个模块单独创建的。没有对跨模块覆盖或多个模块的组合报告的内置支持。
因此仅使用 Maven 和 Jacoco 无法满足您的要求。但是,您可以在企业设置中使用通用方法:Sonarqube,它将处理生成的 jacoco 文件(即
jacoco.exec
)并通过其 Jacoco 集成(在最新版本上开箱即用)聚合报告和治理。
来源:https://www.jacoco.org/jacoco/trunk/doc/check-mojo.html
使用带有计数器指令的 Bundle,这将检查整个项目的整体代码覆盖率:
<rules>
<rule>
<element>BUNDLE</element>
<limits>
<limit>
<counter>INSTRUCTION</counter>
<value>COVEREDRATIO</value>
<minimum>0.80</minimum>
</limit>
</limits>
</rule>
不可能(到目前为止,希望将来也是如此)。但我有另一种方法可以做到这一点。
Jacoco 的目标是为多模块项目创建聚合报告,但它不会创建检查覆盖率指标所需的 jacoco.exec 文件。
一种方法是使用report-aggregate goal创建聚合报告,并为每个模块单独生成jacoco.exec文件,然后使用jacoco-merge goal将其合并。
但是这种方法并不是那么好,因为它只覆盖了直接代码覆盖率。 例如-> 假设你的模块 A 有一些测试覆盖了模块 B 中的某些代码行,在这种情况下合并不会考虑此模块级别的差异,这是因为你首先生成模块级别的 exec 文件,然后将其合并为一个。
我找到了一种更好的总体检查方法。这不需要任何执行文件,您可以仅使用报告聚合目标来完成! 如果您注意到报告聚合目标确实为聚合报告创建了 html、xml 和 csv 文件,我们可以简单地从这些文件中抓取数据并编写验证!
这是我使用 XML 文件实现的
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>${jacoco-maven-plugin.version}</version>
<executions>
<execution>
<id>prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<!-- Aggregate the report after tests run -->
<execution>
<id>report-aggregate</id>
<phase>verify</phase>
<goals>
<goal>report-aggregate</goal>
</goals>
<configuration>
<outputDirectory>
${project.basedir}/target/jacoco-reports
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<phase>verify</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>python3</executable>
<arguments>
<argument>check_coverage.py</argument>
<argument>${code-coverage-percentage}</argument>
</arguments>
</configuration>
</execution>
</executions>
</plugin>
check_coverage.py
import xml.etree.ElementTree as ET
import sys
# Path to the JaCoCo XML report file
jacoco_report_file = 'target/jacoco-reports/jacoco.xml'
# Get the required coverage from the command-line argument
try:
required_coverage = float(sys.argv[1]) # Pass as first argument
except IndexError:
print("Usage: python check_coverage.py <required_coverage>")
sys.exit(1)
except ValueError:
print("Invalid value for required coverage, please provide a numeric value.")
sys.exit(1)
try:
# Parse the XML file
tree = ET.parse(jacoco_report_file)
root = tree.getroot()
# Find the line coverage data
counter = root.findall(".//counter[@type='LINE']")
if not counter:
print("Could not find line coverage data in the JaCoCo report.")
exit(1)
# Pick the last occurrence
last_counter = counter[-1]
# Extract the 'missed' and 'covered' values from the XML
missed = int(last_counter.get('missed', 0))
covered = int(last_counter.get('covered', 0))
print(missed)
print(covered)
# Calculate the total lines and the line coverage percentage
total_lines = missed + covered
if total_lines == 0:
print("No lines were executed or missed, cannot calculate coverage.")
exit(1)
line_coverage = (covered / total_lines) * 100
# Output the calculated coverage
print(f"Line Coverage: {line_coverage:.2f}%")
# Check if the coverage meets the required threshold (e.g., 80%)
# required_coverage = 80.0 # Set your desired threshold here
if line_coverage < required_coverage:
print(f"Coverage is below the required threshold of {required_coverage}%.")
exit(1)
else:
print("Coverage meets the required threshold.")
exit(0)
except FileNotFoundError:
print(f"JaCoCo aggregate report not found at {jacoco_report_file}.")
exit(1)
except ET.ParseError as e:
print(f"Error parsing the JaCoCo XML report: {e}")
exit(1)
只需根据您的要求调整代码覆盖率。
维奥拉!