如何从 dotnet test --collect "Code coverage" 生成的 VS 覆盖率发布 Cobertura 覆盖率报告?

How to publish Cobertura coverage report from the VS coverage produced by dotnet test --collect "Code coverage"?

所以这个过程可以从https://docs.microsoft.com/en-us/azure/devops/pipelines/ecosystems/dotnet-core?view=azure-devops#collect-code-coverage推导出来,包含以下步骤:

  1. 运行 覆盖率 的测试没有 发布测试结果,因为我们需要控制生成的二进制覆盖率报告的位置(参见 )
  2. 将VS二进制覆盖结果转换为XML
  3. 安装报告生成器工具
  4. 使用报告生成器工具将 VS XML 覆盖范围转换为 Cobertura
  5. 使用发布代码覆盖率 Azure DevOps 任务发布 Cobertura 报告
  6. 公布测试结果

可以使用以下 YAML 模板实施这些步骤:

parameters:
  BuildConfiguration: Debug

steps:
- task: DotNetCoreCLI@2
  name: Test
  displayName: Test
  inputs:
    command: 'test'
    publishTestResults: false
    arguments: '-c ${{ parameters.BuildConfiguration }} --no-build -l trx -r $(Common.TestResultsDirectory)\tests --collect "Code coverage"'

- task: PublishTestResults@2
  displayName: Publish Test Results
  inputs:
    testResultsFormat: VSTest
    testResultsFiles: '*.trx'
    searchFolder: $(Common.TestResultsDirectory)\tests
    testRunTitle: $(Build.DefinitionName)-$(Build.BuildNumber)
  condition: succeededOrFailed()

- powershell: |
    $cc = "$(Get-ToolFolderFromNuGet Microsoft.CodeCoverage)\..\build\netstandard1.0\CodeCoverage\CodeCoverage.exe"
    $BinaryCoverageFile = (Get-Item "$(Common.TestResultsDirectory)\tests\*\*.coverage").FullName
    & $cc analyze /output:$(Common.TestResultsDirectory)\vstest-coverage.xml $BinaryCoverageFile
  displayName: Convert Coverage Result To Xml

- task: DotNetCoreCLI@2
  inputs:
    command: custom
    custom: tool
    arguments: install --tool-path . dotnet-reportgenerator-globaltool
  displayName: Install ReportGenerator tool

- script: .\reportgenerator.exe -reports:$(Common.TestResultsDirectory)\vstest-coverage.xml -targetdir:$(Common.TestResultsDirectory)\coverage\report -reporttypes:"Cobertura"
  displayName: Create Cobertura Coverage Report

- task: PublishCodeCoverageResults@1
  displayName: Publish Coverage Results
  inputs:
    codeCoverageTool: 'Cobertura'
    summaryFileLocation: '$(Common.TestResultsDirectory)/coverage/report/Cobertura.xml'
    failIfCoverageEmpty: true

它使用我的 powershell 函数 Get-ToolFolderFromNuGet 从 NuGet 下载包,但除此之外没有使用自定义代码。

无论如何,问题是发布测试结果任务将二进制覆盖率结果作为超链接发布在覆盖率结果应该是的同一选项卡中:

这是没用的。如果我注释掉发布测试结果,覆盖页面显示预期结果:

但现在我失去了测试页面,当然:

有谁知道如何解决这个难题?

P.S.

我在这里打开了一个 bug - https://github.com/microsoft/azure-pipelines-tasks/issues/12670

编辑 1

我试图在最后发布测试结果,甚至删除了二进制覆盖率结果文件。没有任何帮助。

通过检查发布测试结果任务的诊断日志,我设法弄清楚了如何解决它。事实上,从日志中:

2020-04-10T15:48:12.1799774Z ##[debug]pattern: '*.trx'
2020-04-10T15:48:12.1839752Z ##[debug]findPath: 'd:\_wf\TestResults\tests'
2020-04-10T15:48:12.1840795Z ##[debug]statOnly: 'false'
2020-04-10T15:48:12.1843783Z ##[debug]findPath: 'd:\_wf\TestResults\tests'
2020-04-10T15:48:12.1844681Z ##[debug]findOptions.allowBrokenSymbolicLinks: 'true'
2020-04-10T15:48:12.1845119Z ##[debug]findOptions.followSpecifiedSymbolicLink: 'true'
2020-04-10T15:48:12.1845244Z ##[debug]findOptions.followSymbolicLinks: 'true'
2020-04-10T15:48:12.1850467Z ##[debug]  d:\_wf\TestResults\tests (directory)
2020-04-10T15:48:12.1858807Z ##[debug]  d:\_wf\TestResults\testsf627391-dd45-48b3-af92-5213c471eb04 (directory)
2020-04-10T15:48:12.1864156Z ##[debug]  d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29 (directory)
2020-04-10T15:48:12.1868508Z ##[debug]  d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29\In (directory)
2020-04-10T15:48:12.1873069Z ##[debug]  d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29\In\TDC5DFC1BLD24 (directory)
2020-04-10T15:48:12.1880777Z ##[debug]  d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29\In\TDC5DFC1BLD24\tfsbuild_TDC5DFC1BLD24_2020-04-10.11_47_23.coverage (file)
2020-04-10T15:48:12.1884045Z ##[debug]  d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29.trx (file)
2020-04-10T15:48:12.1885576Z ##[debug]7 results

所以在那里找到了二进制覆盖文件。但是它原来的位置不同,我们可以从测试任务本身的常规构建日志中看到:

2020-04-10T15:47:54.0912521Z M i c r o s o f t   ( R )   C o v e r a g e   C o l l e c t i o n   T o o l   V e r s i o n   1 6 . 0 . 3 0 3 1 9 . 3 0 0 2 
2020-04-10T15:47:54.0913009Z  
2020-04-10T15:47:54.0913107Z  
2020-04-10T15:47:54.0913209Z  C o p y r i g h t   ( c )   M i c r o s o f t   C o r p o r a t i o n .     A l l   r i g h t s   r e s e r v e d . 
2020-04-10T15:47:54.0913270Z  
2020-04-10T15:47:54.0913307Z  
2020-04-10T15:47:54.0913340Z  
2020-04-10T15:47:54.0913400Z  
2020-04-10T15:47:54.3182888Z  Results File: d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29.trx
2020-04-10T15:47:54.3183717Z 
2020-04-10T15:47:54.3184201Z Attachments:
2020-04-10T15:47:54.3184419Z   d:\_wf\TestResults\testsf627391-dd45-48b3-af92-5213c471eb04\tfsbuild_TDC5DFC1BLD24_2020-04-10.11_47_23.coverage
2020-04-10T15:47:54.3196805Z Test Run Successful.
2020-04-10T15:47:54.3197219Z Total tests: 445
2020-04-10T15:47:54.3197713Z      Passed: 445
2020-04-10T15:47:54.3199584Z  Total time: 30.1160 Seconds

因此,原始二进制覆盖文件位于 d:\_wf\TestResults\testsf627391-dd45-48b3-af92-5213c471eb04\tfsbuild_TDC5DFC1BLD24_2020-04-10.11_47_23.coverage,但已复制到 d:\_wf\TestResults\tests\tfsbuild_TDC5DFC1BLD24_2020-04-10_11_47_29\In\TDC5DFC1BLD24\tfsbuild_TDC5DFC1BLD24_2020-04-10.11_47_23.coverage

我的错误是只删除了原来的位置。在两个地方都删除后,代码覆盖率页面变得如预期 - 不再有无用的超链接,是的实际覆盖率。

YAML 中更正后的 powershell 任务如下所示:

- powershell: |
    $cc = "$(Get-NuGetPackageBaseFolder Microsoft.CodeCoverage)\build\netstandard1.0\CodeCoverage\CodeCoverage.exe"
    $BinaryCoverageFile = Get-Item "$(Common.TestResultsDirectory)\tests\*\*.coverage"
    & $cc analyze /output:$(Common.TestResultsDirectory)\vstest-coverage.xml $BinaryCoverageFile.FullName
    Remove-Item (Get-ChildItem -Path "$(Common.TestResultsDirectory)\tests" -Recurse -Filter $BinaryCoverageFile.Name).FullName
  displayName: Convert Coverage Result To Xml

当然,发布测试结果任务必须移到此任务之后。

我通过删除 reportgenerator 之后的代码覆盖率文件解决了这个问题。

步骤如下

steps:
  - task: DotNetCoreCLI@2
    displayName: dotnet test
    inputs:
      command: 'test'
      projects: '**/*.Tests.csproj'
      arguments: '--no-build --no-restore --configuration $(BuildConfiguration) --collect "XPlat Code Coverage" --settings CodeCoverage.runsettings --logger trx --results-directory $(Build.SourcesDirectory)/out/TestResults/' 
      publishTestResults: false

  - script: |
        dotnet tool install -g dotnet-reportgenerator-globaltool
        reportgenerator -reports:$(Build.SourcesDirectory)/out/TestResults/**/coverage.cobertura.xml -targetdir:$(Build.SourcesDirectory)/out/CoverageResults "-reporttypes:HtmlInline_AzurePipelines;Cobertura"
    displayName: Create code coverage report

  - task: DeleteFiles@1
    displayName: 'Delete coverage files'
    inputs:
      sourceFolder: $(Build.SourcesDirectory)/out/TestResults
      contents: | 
        \**\*.coverage
        
  - task: PublishTestResults@2
    displayName: 'Publish test results'
    inputs:
      testResultsFormat: VSTest
      testResultsFiles: '$(Build.SourcesDirectory)\out\TestResults\**\*.trx'
      failTaskOnFailedTests: true

  # Publish the combined code coverage to the pipeline
  - task: PublishCodeCoverageResults@1
    displayName: 'Publish code coverage report'
    inputs:
      codeCoverageTool: 'Cobertura'
      summaryFileLocation: '$(Build.SourcesDirectory)/out/CoverageResults/Cobertura.xml'
      reportDirectory: '$(Build.SourcesDirectory)/out/CoverageResults'