如何获取和解析CI管道中所有生成的coverage.cobertura文件?
c#
鉴于具有多个 xUnit 测试项目的 .Net 5 解决方案,我可以dotnet test从解决方案的根目录运行,它将运行所有测试。
我想根据我运行的https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-code-coverage?tabs=windows#integrate-with-net-test生成报告dotnet test --collect:"XPlat Code Coverage"它为每个测试项目生成一个coverage.cobertura 文件。
基于https://docs.microsoft.com/en-us/dotnet/core/testing/unit-testing-code-coverage?tabs=windows#generate-reports我知道我可以安装该dotnet-reportgenerator-globaltool工具并获得可视化的 HTML基于每个coverage.cobertura 文件的报告。
但是我想添加一个 CI 管道,当线路覆盖率低于 x % 时,我想让管道失败。
鉴于以下示例 Gitlab CI 配置
image: mcr.microsoft.com/dotnet/sdk:5.0
stages:
- tests
tests:
stage: tests
script:
- dotnet test --collect:"XPlat Code Coverage"
coverage.cobertura.xml如果值低于例如 80%,我如何收集所有生成的文件,读取行覆盖率并让管道失败?
例子:
tests:
stage: tests
script:
- dotnet test --collect:"XPlat Code Coverage"
# for each coverage.cobertura file found in the test projects
# parse the file
# read the line coverage
# fail if the value is less than 80 percent
如果像 xUnit 这样的工具已经提供了这样的功能,如果我不必重新发明轮子就好了!
编辑:
我知道我也可以使用allow_failure关键字让这个阶段处于警告状态。这对我来说没问题,我只想知道如何从生成的报告中读取所需的信息并验证它们以决定该阶段是否应该通过、失败或不稳定。
回答
这听起来可能是一种非常新手的方法,但这里有一些对我有用的方法。我正在使用 Azure devops 并且我有类似的多个项目,导致每个测试项目有多个 coverage.cobertura 文件
首先,我使用Report Generator 任务将所有覆盖率报告合并为一个,并将其存储在工作目录中。下面是yaml。我正在生成 HtmlFormat 和 Cobertura 报告
- task: Palmmedia.reportgenerator.reportgenerator-build-release-task.reportgenerator@4
displayName: ReportGenerator
inputs:
reports: '$(Build.SourcesDirectory)/**/*cobertura.xml'
targetdir: '$(System.DefaultWorkingDirectory)/CoverageResults'
reporttypes: 'HtmlInline_AzurePipelines;Cobertura'
生成的 cobertura 报告如下所示:
在此之后,我尝试使用 powershell 任务阅读此合并的 xml 报告
- powershell: |
[XML]$coverage = Get-Content $(System.DefaultWorkingDirectory)/CoverageResults/Cobertura.xml
if($coverage.coverage.'line-rate' -ge .50){Write-Host "The value is greater than 50."}else{throw}
displayName: 'PowerShell Script'
在此任务中,我尝试读取覆盖文件,然后访问 line-rate 属性。如果合并报告的行率不大于或等于 50,我将抛出错误。将我的 powershell 任务的 ErrorActionPreference 设置为 Stop 时,如果线路覆盖率不符合预期,管道将停止。您还可以包括其他条件,如分支率以获得更好的准确性。
我想在这方面有很多需要改进的地方,但这只是我能想出的一个快速解决方法。请随时提出改进建议
回答
根据VSTest 集成支持的Coverlet选项,XPlat 代码覆盖率工具不支持合并覆盖率报告文件和验证阈值,但他们正在努力。现在有一个解决方案来合并报告并计算Daniel Paz提供的阈值
他们merge with在 VSTest 版本的工具中使用coverlet.collector:
# set MergeWith value in runsettings.xml
$runsettingsFile = "$pipelineFolder/runsettings.xml"
$coverageJsonFullPath = "$testResultsDirectory/coverage.json"
(Get-Content $runsettingsFile).Replace('#mergewith#', $coverageJsonFullPath) | Set-Content $runsettingsFile
# calculate code coverage
Get-ChildItem -Path "test/unit","test/integration","test/component" -Recurse -Filter *.csproj |
Foreach-Object {
$dir = "$testResultsDirectory/$($_.BaseName)"
dotnet add $_.FullName package coverlet.collector -v 1.1.0
dotnet test $_.FullName --collect:"XPlat Code Coverage" --settings $runsettingsFile --no-build --logger trx --results-directory $dir
Copy-Item -Path "$dir/*/coverage.json" -Destination $coverageJsonFullPath -Force
}
# copy results to $testResultsDirectory
Copy-Item -Path "$dir/*/coverage.cobertura.xml" -Destination $testResultsDirectory
Copy-Item -Path "$dir/*/coverage.opencover.xml" -Destination $testResultsDirectory
运行设置:
<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat code coverage">
<Configuration>
<Format>opencover,json,cobertura</Format>
<MergeWith>#mergewith#</MergeWith>
<Exclude>[*]*Migrations*</Exclude> <!-- [Assembly-Filter]Type-Filter -->
<ExcludeByAttribute>Obsolete,GeneratedCodeAttribute,CompilerGeneratedAttribute</ExcludeByAttribute>
<ExcludeByFile>**/Program.cs,**/test/**/*</ExcludeByFile> <!-- Absolute or relative file paths -->
<SingleHit>false</SingleHit>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
<InProcDataCollectionRunSettings>
<InProcDataCollectors>
<InProcDataCollector assemblyQualifiedName="Coverlet.Collector.DataCollection.CoverletInProcDataCollector, coverlet.collector, Version=1.1.0.0, Culture=neutral, PublicKeyToken=null"
friendlyName="XPlat Code Coverage"
enabled="True"
codebase="coverlet.collector.dll" />
</InProcDataCollectors>
</InProcDataCollectionRunSettings>
</RunSettings>
并检查合并文件的阈值:
# compare code coverage to $coverageThreshold
$coverage = Select-Xml -Path "$testResultsDirectory/coverage.cobertura.xml" -XPath "/coverage/@branch-rate" | % {[double]::Parse($_.Node.Value) * 100}
Write-Output "Coverage is $coverage"
if ($coverage -lt $coverageThreshold) {
throw "Code coverage $coverage is less than threshold $coverageThreshold"
}