6

I want to generate a single coverage report for my C# project based on this tutorial

https://learn.microsoft.com/en-us/dotnet/core/testing/unit-testing-code-coverage

When starting a Gitlab CI pipeline with the following configuration

image: mcr.microsoft.com/dotnet/sdk:5.0

stages:
  - build
  - unit-tests

build:
  stage: build
  script:
    - dotnet build --output build
  artifacts:
    paths:
      - build

unit-tests:
  stage: unit-tests
  script:
    - |-
      dotnet test --no-build --output build --collect:"XPlat Code Coverage";
      
      dotnet tool install -g dotnet-reportgenerator-globaltool;

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

I get the following error

The report file pattern '**/coverage.cobertura.xml' is invalid. No matching files found.

When using ls to inspect the directory before running the reportgenerator command I can see that there are no matching files (although they should exist).

I would expect to have one coverage.cobertura.xml file per test project e.g.

  • ...\myRepo\xUnitTestProject1\TestResults\380e65f7-48d5-468f-9cbc-550c8e0aeda8\coverage.cobertura.xml
  • ...\myRepo\xUnitTestProject2\TestResults\c96c55f7-40d3-483e-a136-573615e3a9c3\coverage.cobertura.xml

My current solution:

It seems I have to run the build again. So I replaced this line

dotnet test --no-build --output build --collect:"XPlat Code Coverage";

with

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

Now it's working fine but an additional build seems to be redundant because I already created a build artifact...


So do you have any ideas how to improve the configuration so that I don't have to build a second time?

  • Which file do you except "coverage.cobertura.xml" or "Cobertura.xml"? try add "ls; ls CoverageReports;" after "reportgenerator" for debuging. – Novikov Aug 01 '21 at 20:19
  • @Novikov the generated file should be `.\CoverageReports\Cobertura.xml`. The command `ls` prints the existing folder `CoverageReports` –  Aug 02 '21 at 12:57
  • Try to replace `**` with a valid address or `..`. It seems that the path pattern is wrong. And be sure that `targetdir` is correct. – mohabbati Aug 03 '21 at 15:51
  • Looks like this article describes somewhat similar to what you're trying to achieve: https://dejanstojanovic.net/aspnet/2020/may/setting-up-code-coverage-reports-in-azure-devops-pipeline/. Note a couple of things: 1) The `reports` syntax is this: `-reports:$(Agent.TempDirectory)/**/coverage.cobertura.xml` 2) Report generating step is a separate task rather than an additional line in the main script. The reason for that is that once installed, the tool will be available in the new session of bash (on Linux) or cmd (on Windows). – Yan Sklyarenko Aug 04 '21 at 11:48
  • After this line `dotnet test --collect:"XPlat Code Coverage";` is executed, have you checked that `coverage.cobertura.xml` files are located where you expect them to be? – Yan Sklyarenko Aug 06 '21 at 07:44
  • yes, I debugged again. I updated my question and found a solution ... any improvements? –  Aug 06 '21 at 12:13

1 Answers1

0

It seems like you could combine the two steps since dotnet test will also trigger a build. You would have build problems reported from the same stage as tests, but both have similar responses.

image: mcr.microsoft.com/dotnet/sdk:5.0

stages:
  - unit-tests


unit-tests:
  stage: unit-tests
  script:
    - |-
      dotnet test --output build --collect:"XPlat Code Coverage";
      
      dotnet tool install -g dotnet-reportgenerator-globaltool;

      reportgenerator -reports:'../coverage.cobertura.xml' -targetdir:'CoverageReports' -reporttypes:'Cobertura';
  artifacts:
    paths:
      - build
    reports:
      cobertura: CoverageReports/Cobertura.xml

Alternatively: Coverlet Collector depends on CoreCompile. But, the Global tool does not (since it isn't an msbuild task).

image: mcr.microsoft.com/dotnet/sdk:5.0

stages:
  - build
  - unit-tests

build:
  stage: build
  script:
    - dotnet build --output build
  artifacts:
    paths:
      - build

unit-tests:
  stage: unit-tests
  script:
    - |-
      dotnet test --no-build --output build --collect:"XPlat Code Coverage";

      dotnet tool install -g coverlet.console;

      dotnet tool install -g dotnet-reportgenerator-globaltool;

      coverlet /path/to/test-assembly.dll --target "dotnet" --targetargs "test /path/to/test-project --no-build";


      reportgenerator -reports:'../coverage.cobertura.xml' -targetdir:'CoverageReports' -reporttypes:'Cobertura';
  artifacts:
    reports:
      cobertura: CoverageReports/Cobertura.xml
  dependencies:
    - build

Coverlet's global tool also supports a --format cobertura option that may help to simplify this further.

Digital Coyote
  • 326
  • 2
  • 12
  • 1
    is it possible to replace `coverlet /path/to/test-assembly.dll --target "dotnet" --targetargs "test /path/to/test-project --no-build";` with a command targeting every test project found in the directory? It would be a mess to list all of them – Question3r Aug 07 '21 at 16:04
  • If my understanding is correct from the [documentation](https://github.com/coverlet-coverage/coverlet/blob/master/Documentation/GlobalTool.md) it's passing the commands to [dotnet test](https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-test), so you should be able to target the solution file instead. – Digital Coyote Aug 07 '21 at 16:43