如何检查 cobertura.xml 文件的代码/测试覆盖率是否高于指定的阈值?

问题描述

我有一个包含多个项目和多个测试项目的 .Net 5 解决方案。我想确保 一切 或指定的百分比值(例如 80%)都被测试覆盖。我正在使用 xUnit 进行测试,并根据文档创建了以下 Powershell 脚本

https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-code-coverage?tabs=windows#generate-reports

dotnet test --collect:"XPlat Code Coverage";

reportgenerator -reports:'**/coverage.cobertura.xml' -targetdir:'CoverageReports' -reporttypes:'Cobertura';

[XML]$report = Get-Content CoverageReports/Cobertura.xml

if($report.coverage.'line-rate' -ge 20)
{
    Write-Host "greater or equal than 20"
}
else
{
    Write-Host "less than 20"
}

Read-Host -Prompt 'done'

执行以下操作

  • 它运行测试并为每个测试项目创建一个 cobertura 文件
  • 它将每个 cobertura 文件合并为一个文件并将其放入 CoverageReports 目录
  • 它解析 .xml 文件

现在我可以访问覆盖信息,例如线速。我怎样才能实现以下示例,而不是虚拟的 if 语句?

if($report.coverage.percentage -lt 80)
{
    Write-Host "Coverage is less than 80 percent"
}

作为奖励,我可以写下尚未涵盖的内容列表。


这是从一个虚拟项目生成的 Cobertura.xml 文件内容

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE coverage SYstem "http://cobertura.sourceforge.net/xml/coverage-04.dtd">
<coverage line-rate="1" branch-rate="1" lines-covered="4" lines-valid="4" branches-covered="0" branches-valid="0" complexity="4" version="0" timestamp="1627911309">
  <sources>
    <source>C:\</source>
  </sources>
  <packages>
    <package name="ClassLibrary1" line-rate="1" branch-rate="1" complexity="3">
      <classes>
        <class name="ClassLibrary1.BoolReturner" filename="C:\...\ClassLibrary1\BoolReturner.cs" line-rate="1" branch-rate="1" complexity="3">
          <methods>
            <method name="Get" signature="(...)" line-rate="1" branch-rate="1" complexity="1">
              <lines>
                <line number="5" hits="3" branch="false" />
              </lines>
            </method>
            <method name="GetFalse" signature="()" line-rate="1" branch-rate="1" complexity="1">
              <lines>
                <line number="6" hits="1" branch="false" />
              </lines>
            </method>
            <method name="X" signature="()" line-rate="1" branch-rate="1" complexity="1">
              <lines>
                <line number="7" hits="1" branch="false" />
              </lines>
            </method>
          </methods>
          <lines>
            <line number="5" hits="3" branch="false" />
            <line number="6" hits="1" branch="false" />
            <line number="7" hits="1" branch="false" />
          </lines>
        </class>
      </classes>
    </package>
    <package name="ClassLibrary2" line-rate="1" branch-rate="1" complexity="1">
      <classes>
        <class name="ClassLibrary2.StringCombiner" filename="C:\...\StringCombiner.cs" line-rate="1" branch-rate="1" complexity="1">
          <methods>
            <method name="Combine" signature="(...)" line-rate="1" branch-rate="1" complexity="1">
              <lines>
                <line number="7" hits="2" branch="false" />
              </lines>
            </method>
          </methods>
          <lines>
            <line number="7" hits="2" branch="false" />
          </lines>
        </class>
      </classes>
    </package>
  </packages>
</coverage>

解决方法

Cobertura 报告将线路覆盖信息作为“线路速率”属性提供。它包含 0 到 1 范围内的值(1 表示 100%)。属性 'line-rate' 在不同级别定义:对于整个报告 - coverage 根元素;对于特定程序集 - package 元素;对于特定类 - class 元素等。

如果目标是检查整个报告(整个代码库)的代码覆盖率,可以使用流动的代码片段来实现

[XML]$report = Get-Content CoverageReports/Cobertura.xml

if ($report.coverage.'line-rate' -lt 0.8) {
  Write-Host "Coverage is less than 80 percent"
}

如果应该更有选择性地检查代码覆盖率,例如在类级别,那么代码片段可能如下

[XML]$report = Get-Content CoverageReports/Cobertura.xml

# Select all rows with line-rate < 0.8 (80%).
$classes = $report.SelectNodes('//class[@line-rate < 0.8]');

# Check number of selected rows.
if ($classes.Count -gt 0) {
  Write-Host "Coverage is less than 80 percent"

  #Write list of files with low coverage.
  $classes | Sort-Object -Property 'line-rate' | Format-Table -Property 'line-rate',filename
}

在此示例中,使用 XPath 表达式 //class[@line-rate < 0.8] 选择具有低覆盖率的类列表。它选择所有 class 属性值小于 0.8 (80%) 的 line-rate 元素。


另外,当需要更复杂的数据分析时,可以代替XPath,直接在PS代码中编写类似的逻辑,例如

[XML]$report = Get-Content CoverageReports/Cobertura.xml

$classes = $report.SelectNodes('//class');
$lowCoverage = $false;

foreach($class in $classes){

  # Convert line-rate value to 0..100% range.
  $percentage = [int](100.0 * [double]$class.'line-rate');

  if ($percentage -lt 80) {
    Write-Host $class.filename " [$percentage%]"
    $lowCoverage = $true;
  }
}

if ($lowCoverage) {
  Write-Host "Coverage is less than 80 percent"
}

可以在以下问题的答案中找到高级 XML 处理技术 ForEach in XML file with PowerShell 个问题。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...