.NET test coverage
Checking the test coverage of your .NET project with SonarQube Cloud’s coverage reporting tools is an essential part of the development process.
SonarQube Cloud supports the reporting of test coverage information as part of the analysis of your .NET project.
However, SonarQube Cloud does not produce the coverage report itself. Instead, you must set up a third-party tool to produce the report as part of your build process. You then need to configure your analysis to tell the SonarScanner where the report is located so that it can pick it up and send it to SonarQube Cloud, where it will be displayed on your project dashboard along with the other analysis metrics.
SonarQube Cloud supports the following .NET test coverage tools:
dotnet-coverage Code Coverage
Follow the tutorial
When you import your .NET project into SonarQube Cloud, you will be guided through the setup process by an in-product tutorial. Once you have completed the tutorial, you should have a working analysis setup. The next step is to adjust that setup to enable coverage reporting.
The .NET scanner comes in four variants depending on which version of .NET and which CI you are using (.NET Framework, .NET Core, .NET Global Tool, and the Azure DevOps Extension). The setup is slightly different for each variant (see the Introduction to SonarScanner for .NET and Azure DevOps Extension sections for more details), but the essential steps are the same.
The analysis is always split into two parts in your build process; the begin step and the end step. In between, you perform the actual build and your tests. To enable coverage reporting, you need to make the following changes:
In the scanner
beginstep, add the appropriate parameter to specify the location of the coverage report file that will be produced.Just after the
buildstep but before the scannerendstep, ensure that yourteststep produces the coverage report file.
Examples using the .NET tool scanner variant
The SonarScanner for .NET comes in four major variants: .NET Framework, .NET Core, .NET Global Tool, and the Azure Pipelines extension.
dotnet-coverage
This is a modern alternative to the Visual Studio Code Coverage provided by Microsoft (see above) that outputs results in the same format, is cross-platform and not dependent on having Visual Studio installed. It requires .NET Core 3.1 or later.
To use dotnet-coverage, you can install it as a local or global dotnet tool:
dotnet tool install --global dotnet-coverageUsing this tool, your build script would look like something like this:
dotnet sonarscanner begin /k:"<sonar-project-key>"
/d:sonar.token="<sonar-token>"
/d:sonar.cs.vscoveragexml.reportsPaths=coverage.xml
dotnet build --no-incremental
dotnet-coverage collect "dotnet test" -f xml -o "coverage.xml"
dotnet sonarscanner end /d:sonar.token="<sonar-token>"Note that we specify the path to the reports using sonar.cs.vscoveragexml.reportsPaths because this tool’s output format is the same as the Visual Studio Code Coverage tool. See the Test coverage parameters page for information about this parameter. The code sample above uses the -f xml parameter to specify that the output format is in XML.
Visual Studio Code Coverage
We only recommend the use of this tool when the build agent has Visual Studio Enterprise installed or when you are using an Azure DevOps Windows image for your build. In these cases, the .NET Framework scanner will automatically find the coverage output generated by the --collect "Code Coverage" parameter without requiring an explicit report path setting. It will also automatically convert the generated report to XML. No further configuration is required. Here is an example:
SonarScanner.MSBuild.exe begin /k:"<sonar-project-key>" /d:sonar.token="<sonar-token>"
dotnet build --no-incremental
dotnet test --collect "Code Coverage"
SonarScanner.MSBuild.exe end /d:sonar.token="<sonar-token>"dotCover
To use dotCover you must install it as a global dotnet tool:
dotnet tool install --global JetBrains.dotCover.CommandLineToolsUsing this tool, your build script would look like something like this:
dotnet sonarscanner begin /k:"<sonar-project-key>"
/d:sonar.token="<sonar-token>"
/d:sonar.cs.dotcover.reportsPaths=dotCover.Output.html
dotnet build --no-incremental
dotnet dotcover test --dcReportType=HTML
dotnet sonarscanner end /d:sonar.token="<sonar-token>"Note that the code sample above specifies the path to the reports using sonar.cs.dotcover.reportsPaths because it is using dotCover; see the Test coverage parameters page for information about this parameter.
OpenCover
To use OpenCover you must download it from OpenCover releases page and unzip it in an appropriate directory, for example: C:\tools\opencover
When using OpenCover, your build script would look like something like this:
dotnet sonarscanner begin /k:"<sonar-project-key>"
/d:sonar.token="<sonar-token>"
/d:sonar.cs.opencover.reportsPaths=coverage.xml
dotnet build --no-incremental
& C:\tools\opencover\OpenCover.Console.exe -target:"dotnet.exe"
-targetargs:"test --no-build"
-returntargetcode
-output:coverage.xml
-register:user
dotnet sonarscanner end /d:sonar.token="<sonar-token>"Note that the code sample specifies the path to the reports using sonar.cs.opencover.reportsPaths because it is using OpenCover. See the Test coverage parameters page for information about this parameter.
Coverlet
To use Coverlet, you must install it as a global dotnet tool:
dotnet tool install --global coverlet.consoleYou also have to install the coverlet collector NuGet package on your test project.
When using Coverlet, your build script would look like something like this:
dotnet sonarscanner begin /k:"<sonar-project-key>"
/d:sonar.token="<sonar-token>"
/d:sonar.cs.opencover.reportsPaths=coverage.xml
dotnet build --no-incremental
coverlet .\CovExample.Tests\bin\Debug\net6.0\CovExample.Tests.dll
--target "dotnet"
--targetargs "test --no-build"
-f=opencover
-o="coverage.xml"
dotnet sonarscanner end /d:sonar.token="<sonar-token>"Note that the code sample specifies the path to the reports in sonar.cs.opencover.reportsPaths because Coverlet produces output in the same format as OpenCover. See the Test coverage parameters page for information about this parameter.
.NET Framework and .NET Core scanners
In most of the examples above, we use the .NET tool scanner variant. If you use the .NET Framework or .NET Core scanner, the commands will be a bit different but the pattern will be the same. See the Installing the scanner page for details.
Azure DevOps extension for SonarQube
Using the Azure DevOps extension for SonarQube and Visual Studio Code Coverage with a C# project, your azure-pipelines.yml would look something like the example below.
Note that with the Azure DevOps extension for SonarQube, the scanner begin step is handled by the SonarCloudPrepare task and the scanner end step is handled by the SonarCloudAnalyze task. Details about these properties are found on the Azure DevOps Extension for SonarQube Cloud page.
Also note in the code sample below, that because the build is running on Windows (vmImage: windows-latest), the pipeline does not need to explicitly define the path to the coverage report; this is evident because sonar.cs.vscoveragexml.reportsPaths is not included.
Additionally, you need to run codecoverage.exe to convert the report to XML. Here is a code sample, to be named azure-pipelines.yml in your files:
trigger:
- master
variables:
- name: system.debug
value: true
pool:
vmImage: windows-latest
steps:
- task: DotNetCoreCLI@2
inputs:
command: 'restore'
projects: '<YourProject.sln>'
feedsToUse: 'select'
- task: SonarCloudPrepare@3
inputs:
SonarCloud: '<YourSonarQubeServiceEndpoint>'
organization: '<YourOrganizationName>'
scannerMode: 'dotnet'
projectKey: '<YourProjectKey>'
projectName: '<YourProjectName>'
- task: DotNetCoreCLI@2
inputs:
command: 'build'
projects: '<YourProject.sln>'
- task: DotNetCoreCLI@2
inputs:
command: 'test'
projects: 'tests/**/*.csproj'
arguments: '--collect "Code Coverage"'
- task: SonarCloudAnalyze@3VB.NET
The examples above are all for C# projects. The setup is identical for VB.NET projects except that you would use these parameters:
sonar.vbnet.vscoveragexml.reportsPathsfor Visual Studio Code Coveragesonar.vbnet.dotcover.reportsPathsfor dotCoversonar.vbnet.opencover.reportsPathsfor OpenCover or Coverlet
See the Test coverage parameters section for information about these parameters.
The parameter sonar.vbnet.ncover3.reportsPaths was formerly used for or NCover3 . This parameter has been deprecated.
Troubleshooting the import of the coverage report
Troubleshooting guide
See the Troubleshooting guide for .NET code coverage import.
Additional notes
Invalid file path
When using the UserSourceLink option of your tool, the coverage report is generates with source link URIs instead of system paths. You may need to turn off this option to use system paths as the source input for file coverage.
Last updated
Was this helpful?

