Collecting code coverage information with dotnet test

Posted: (EET/GMT+2)

 

As Microsoft puts it, "Code coverage is a measurement of the amount of code that is run by unit tests - either lines, branches, or methods." If you want a quick code coverage report from a .NET test project, you do not need to start from Visual Studio.

For a lighter tooling, you can use the command dotnet test to run a data collector during the test run.

One of such tools is the Coverlet tool, available as a NuGet package. To add it to a test project, first add the package:

dotnet add package coverlet.collector

Then run the tests with the Coverlet data collector enabled:

dotnet test --collect:"XPlat Code Coverage"

The important part is --collect. It tells the test platform to run an additional data collector while the tests execute.

After the test run completes, the coverage file is written under the TestResults folder.

TestResults
    6f0c8d8f-3c6e-4b41-9dd8-5fd5a3d20f1a
        coverage.cobertura.xml

The exact folder name changes on each run.

Note that Coverlet's collector name is XPlat Code Coverage. The result is commonly written in Cobertura XML format, which many tools can read.

This is different from the older Visual Studio code coverage workflow. Visual Studio has had code coverage features for a long time, but this approach works directly from the command line and is useful in build scripts and CI pipelines.

A typical test project file includes the test SDK, the test framework, and the Coverlet collector:

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <TargetFramework>net6.0</TargetFramework>
    <IsPackable>false</IsPackable>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.0.0" />
    <PackageReference Include="xunit" Version="2.4.0" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
    <PackageReference Include="coverlet.collector" Version="3.0.0" />
  </ItemGroup>

</Project>

If you do not want to pin the version manually, use dotnet add package and let NuGet choose the current (latest) version.

For a more readable HTML report, use ReportGenerator after the test run:

dotnet tool install --global dotnet-reportgenerator-globaltool

Then generate the report:

reportgenerator ^
    -reports:"TestResults\*\coverage.cobertura.xml" ^
    -targetdir:"CoverageReport" ^
    -reporttypes:Html

Open the generated report from:

CoverageReport\index.html

This is a good way to check whether tests really cover the code path you think they cover. Passing tests and useful coverage are not the same thing.

For CI pipelines, the same basic command is usually enough as a first step:

dotnet test --collect:"XPlat Code Coverage"

From there, publish the Cobertura file or generate an HTML report depending on the build system. Oh, there's also a sample project for the new .NET 6.0 available here.

Happy testing!