Pages

Wednesday, May 07, 2025

Beautiful html coverage reports in C# with Cobertura

Coverage reports in C# with Cobertura

In the last contract I completed, we were building WebAPI microservices in C#, and part of our build process was to run all of our XUnit (and, depending on who originally wrote the microservice, maybe NUnit) tests and use SonarCloud to produce a pretty amazingly specific coverage report that highlighted every source file's test status, line-by-line.

I've got a personal project in C#, have been spending time recently writing tests for it, and wondered if I could pull off the same level of coverage testing.

Turns out I can! Exactly the same!

Install by adding a ref to the coverlet collector to your testing proj:

dotnet add package coverlet.collector

Then run the test with this:

dotnet test --collect:"XPlat Code Coverage"

After the above command is run, a coverage.cobertura.xml file containing the results will be published to the TestResults directory as an attachment.

And sure enough, there's a new folder with every run in my C:\path\to\app\MyTestingProjectFolder\TestResults folder. The cobertura file is in painfully named folders like 946f0f00-2eec-4cef-b734-e683d4e258aa, but open the latest and you can see the XML.

Now the XML isn't very interesting.

<coverage line-rate="0.4882" branch-rate="0.465" version="1.9" timestamp="1745620667" lines-covered="1101" lines-valid="2255" branches-covered="299" branches-valid="643">
    <sources>
        <source>C:\path\to\app\MyApp\</source>
    </sources>
    <packages>
        <package name="MyAppPackage" line-rate="0.4882" branch-rate="0.465" complexity="734">
    <classes>
        <class name="Program" filename="Program.cs" line-rate="0" branch-rate="1" complexity="2">
    <methods>
        <method name="<Main>$" signature="(System.String[])" line-rate="0" branch-rate="1" complexity="1">
            <lines>
                <line number="16" hits="0" branch="False"/>
                <line number="20" hits="0" branch="False"/>
            </lines>
    </method>
<!-- ... -->

You have to turn that into a more interesting report.

This Stackoverflow answer explains how:

This tool quickly generate Html reports from coverage file. Works quite well and does not require complex activities, can be easily included in the build process.

From the README:

Install:

dotnet tool install -g dotnet-reportgenerator-globaltool

Run:

reportgenerator [options]

which, in my case, if I'm already in the same folder as the coverage.cobertura.xml file, looks like this:

reportgenerator -reports:".\coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html

... which, because we said so in the options, creates a folder named coveragereport in the same dir, and within that are two html files that are identical except for their file extensions, index.htm and index.html. Far be it for a Microsoft-adjacent tool to stop producing three-letter file extensions.

And then that report looks incredible:

I have no idea why I redacted so much of that. Also note this is running against a very early stage piece of code. This coverage is obviously horrendous. But the coverage report isn't!