Testing Coverage Report Generator

“ReportGenerator converts coverage reports generated by coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover, gcov, or lcov into human readable reports in various formats. The reports show the coverage quotas and also visualize which lines of your source code have been covered.” - https://www.nuget.org/packages/dotnet-reportgenerator-globaltool

ReportGenerator tool wont replace Sonarqube as its not a Clean as You Code type methodology but if you want to locally and quickly check code coverage using generated reports, its a winner.

Simple Demo

These steps are for a .Net Core application but you can apply them to any code base that has coverlet.collector installed in the tests project.

  1. Clone https://github.com/carlpaton/CoverageReportGeneratorDemo to c:\dev\CoverageReportGeneratorDemo, this is a net8.0 SDK-style project.

  2. Check that you can build it

1
2
c:\dev\CoverageReportGeneratorDemo
dotnet build
  1. Install the .NET Core version of ReportGenerator - dotnet-reportgenerator-globaltool, here Im using the path tools which is excluded in .gitignore
1
dotnet tool install dotnet-reportgenerator-globaltool --tool-path tools --version 5.3.9
  1. Set the cover format and ensure you have coverlet.collector installed.

CoverageReportGeneratorDemo already has coverlet.collector 6.0.0 installed, it came with the scaffold template from Microsoft when I created the test project and selected xUnit Test Project

As mentioned in at the top coverlet.collector can generate coverage results in multiple formats. The usual opencover format is no longer maintained 😔 and when I tested with the default json format this resulted in no coverage, perhaps there is more settings I missed. 🤷

I next tested with cobertura in my .runsettings file and this worked, so I rolled with it.

1
2
3
4
5
6
7
8
9
10
11
12
<?xml version="1.0" encoding="utf-8" ?>
<RunSettings>
<DataCollectionRunSettings>
<DataCollectors>
<DataCollector friendlyName="XPlat code coverage">
<Configuration>
<Format>cobertura</Format>
</Configuration>
</DataCollector>
</DataCollectors>
</DataCollectionRunSettings>
</RunSettings>
  1. Run the tests specifying the .runsettings file
1
dotnet test --settings="./Cover.Tests/.runsettings"

This then results in an attachment coverage.cobertura.xml:

C:\dev\CoverageReportGeneratorDemo\Cover.Tests\TestResults\10e130bb-7829-4a36-bef3-bf16119422c8\coverage.cobertura.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="utf-8"?>
<coverage line-rate="0.4285" branch-rate="1" version="1.9" timestamp="1726637911" lines-covered="3" lines-valid="7" branches-covered="0" branches-valid="0">
<sources>
<source>C:\dev\CoverageReportGeneratorDemo\Cover\</source>
</sources>
<packages>
<package name="Cover" line-rate="0.4285" branch-rate="1" complexity="3">
<classes>
<class name="Program" filename="Program.cs" line-rate="0" branch-rate="1" complexity="1">
<methods>
<method name="&lt;Main&gt;$" signature="(System.String[])" line-rate="0" branch-rate="1" complexity="1">
<lines>
<line number="2" hits="0" branch="False" />
</lines>
</method>
</methods>
<lines>
<line number="2" hits="0" branch="False" />
</lines>
</class>
<class name="Cover.SumCode" filename="SumCode.cs" line-rate="0.5" branch-rate="1" complexity="2">
<methods>
<method name="Sum" signature="(System.Int32,System.Int32)" line-rate="1" branch-rate="1" complexity="1">
<lines>
<line number="8" hits="1" branch="False" />
<line number="9" hits="1" branch="False" />
<line number="10" hits="1" branch="False" />
</lines>
</method>
<method name="Sum2" signature="(System.Int32,System.Int32)" line-rate="0" branch-rate="1" complexity="1">
<lines>
<line number="13" hits="0" branch="False" />
<line number="14" hits="0" branch="False" />
<line number="15" hits="0" branch="False" />
</lines>
</method>
</methods>
<lines>
<line number="8" hits="1" branch="False" />
<line number="9" hits="1" branch="False" />
<line number="10" hits="1" branch="False" />
<line number="13" hits="0" branch="False" />
<line number="14" hits="0" branch="False" />
<line number="15" hits="0" branch="False" />
</lines>
</class>
</classes>
</package>
</packages>
</coverage>

You dont have to use the runsettings file, you can instead just pass collect="XPlat Code Coverage", where XPlat just means cross platform, the resulting file is coverage.cobertura.xml, I thought it would be coverage.json but it wasnt.

1
dotnet test --collect="XPlat Code Coverage"

If you have other test projects you can use filter, here Im filtering where the project name is like UnitTests

1
2
c:\dev\CoverageReportGeneratorDemo
dotnet test --collect="XPlat Code Coverage" --filter FullyQualifiedName~UnitTests
  1. Run the reportgenerator tool passing coverage report and target directory as arguments
1
2
3
./tools/reportgenerator.exe `
-reports:Cover.Tests/TestResults/10e130bb-7829-4a36-bef3-bf16119422c8/coverage.cobertura.xml `
-targetdir:report/
  1. A html report is then generated in c:\dev\CoverageReportGeneratorDemo\report which shows what paths have coverage and which do not, the attribute ExcludeFromCodeCoverage is supported out of the box. Previously Ive had to install coverlet.msbuild to get this to work.

html-report

You can see my generated html report here

References