4

First, some context: I have a Visual Studio solution containing several production class libraries and nine unit test projects. All the projects are targeting .NET 5. I am running .NET 5.0.401. All unit test projects have references to coverlet.collector. I do not use the older coverlet.msbuild package. From my reading, using XPlat Code Coverage is now idiomatic for .NET Core.

I have an Azure Pipelines pipeline that I use for CI builds. As a part of this pipeline, I want to run all the unit tests, generate unit test results for upload to Pipelines, and generate code coverage results for upload to Pipelines. I've already read several blog articles and documentation that would seem to make this simple; however, I've found it's anything but.

Let's start simple by running some commands on my local workstation. For the purposes of this exercise we will assume I have already successfully built the solution using this command:

dotnet build Solution.sln --configuration Debug

If I run tests like this:

dotnet test Solution.sln --configuration Debug --no-build --no-restore --collect:"XPlat Code Coverage" --results-directory artifacts/test-results

then I see code coverage results stored in subdirectories named after GUIDs. Why Microsoft decided to do this I have no idea, but that's out of my control.

Cobertura code coverage results

(After running this command and taking the screenshot, I deleted the test-results directory.)

Remember that I also want to generate unit test results. To do that, I add the --logger trx parameter to the same command line. This time, lots of other folders are created that contain what appear to be duplicate code coverage results. Additionally, I get the .trx files I'm looking for.

Duplicate code coverage results

You'll notice there are an additional nine code coverage reports in addition to the nine .trx files I want.

Similar duplicate files are generated on my self-hosted Pipelines build agent. In Pipelines, if I try to execute the following task:

- task: 'PublishCodeCoverageResults@1'
  displayName: 'Publish code coverage results'
  inputs:
    codeCoverageTool: 'Cobertura'
    summaryFileLocation: 'artifacts/test-results/**/coverage.cobertura.xml'

I get an error:

##[warning]Multiple file or directory matches were found. Using the first match: C:\agent\_work\38\s\artifacts\test-results\$redacted\In\redacted\coverage.cobertura.xml
##[error]No code coverage results were found to publish.

The directory it's reporting here is not one of the GUID directories generated when I omit --logger trx but instead one of the duplicate directories.

This answer seems to indicate I'm doing everything properly. I've also posted a comment on that answer hoping for some assistance.

I have several questions:

  1. Am I invoking dotnet test correctly in order to generate code coverage results and .trx files at the same time?
  2. Does dotnet test support this scenario?
  3. Is the function of the ReportGenerator extension in the Azure Pipelines marketplace actually built into dotnet now?
  4. Which code coverage results are the "real" ones? Do I need to copy the GUID folders to another location before publishing code coverage results?
  5. I want to specify a RunSettings file in order to do things like exclude members with certain attributes from being considered by the code coverage engine. Is RunSettings compatible with my workflow?
NathanAldenSr
  • 7,841
  • 4
  • 40
  • 51

1 Answers1

1

If you have multiple coverage files, you need merge them first before you publish. You may achieve this with following:

  - task: DotNetCoreCLI@2
    displayName: "dotnet test"
    inputs:
      command: test
      projects: "*.sln"
      publishTestResults: true
      arguments: -c Release --no-restore --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=cobertura

  - task: reportgenerator@4
    displayName: "Merge code coverage reports"
    inputs:
      reports: "**/coverage.cobertura.xml"
      targetdir: "$(Build.ArtifactStagingDirectory)/coverlet"
      reporttypes: "Cobertura"
      verbosity: "Verbose"

  - task: PublishCodeCoverageResults@1
    displayName: "Publish code coverage results"
    inputs:
      codeCoverageTool: Cobertura
      summaryFileLocation: "$(Build.ArtifactStagingDirectory)/coverlet/Cobertura.xml"

Note: some parameters probably need to be adjusted to your porject (like directories where you expect to have cobertura files).

I don't have in my code specifig logger for trx and I see in logs that they are produced.

If you want to pass runsettings please check this doc - Configure a test run.

Krzysztof Madej
  • 32,704
  • 10
  • 78
  • 107
  • If you take a look at the answer I linked to in my question, it would seem that Microsoft *allegedly* built in the ReportGenerator function into `dotnet` itself. I don't have any authoritative source from MS for that, though. – NathanAldenSr Sep 29 '21 at 14:07
  • Also, your example uses the old `coverlet.msbuild` method of doing this, which is basically deprecated in favor of `coverlet.collector` for later versions of .NET Core. – NathanAldenSr Sep 29 '21 at 14:07
  • I should also state that at one point I was using the `ReportGenerator` extension to combine Cobertura code coverage results and still wasn't able to get this to work. – NathanAldenSr Sep 29 '21 at 14:09
  • Here the most important part is merge. Did you try that before publish? – Krzysztof Madej Sep 29 '21 at 14:38
  • Yes, I did try merging files (in fact, I spent days assuming I needed to). I just noticed that you are actually the author of the other answer I linked to. I am curious why in that answer's update you say that the merging functionality of ReportGenerator is included in `dotnet` natively. Your updated answer implies the `PublishCodeCoverageResults` task can merge several files. Why won't it work in my case? – NathanAldenSr Sep 30 '21 at 12:43
  • Here is the source for my `coverlet.collector` comment: https://github.com/coverlet-coverage/coverlet/issues/859 – NathanAldenSr Sep 30 '21 at 12:55
  • 1
    It was not me who updated the answer. I didn't verified that. But I think I have to. Thanks for rising this. – Krzysztof Madej Sep 30 '21 at 13:00
  • I'm continue to experiment with this. I added a build step to delete all the non-GUID-named folders that contain the duplicate results. As soon as I did this, the publish step failed... but it appears to have only uploaded a single file. It looks like the `dotnet` CLI does not, in fact, handle automatic packaging of multiple results files. Next step is to once again try ReportGenerator now that I've figured out the duplicate results are somehow problems. – NathanAldenSr Oct 01 '21 at 13:43
  • Sorry, I meant the publish step _succeeded_. – NathanAldenSr Oct 01 '21 at 13:54
  • An update: I published the raw test results from my pipeline as a build artifacts. It turns out many of the `coverage.cobertura.xml` files are actually empty! I'm not sure why. It also seems like `ReportGenerator` is still required. I'll go ahead and mark your answer as the answer since it seems like your recommendation is still the correct one. – NathanAldenSr Oct 01 '21 at 15:15