Start Free
Latest | Analyzing source code | Test coverage | .NET test coverage

.NET test coverage

On this page

SonarQube Server supports the reporting of test coverage information as part of the analysis of your .NET project.

However, SonarQube Server does not generate 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 Server, where it will be displayed on your project dashboard along with the other analysis metrics.

SonarQube Server supports the following .NET test coverage tools:

  • Visual Studio Code Coverage
  • dotnet-coverage Code Coverage
  • dotCover
  • OpenCover
  • Coverlet

Additionally, a generic coverage format is also supported if you wish to use an unsupported tool (though you will have to convert its output to the generic format yourself). In this section, we discuss the directly supported tools. For information on the generic format, seeĀ Generic test data.

Adding coverage to your build process

The SonarScanner for .NET comes in four variants depending on which version of .NET and which CI you are using (.NET Framework,Ā .NET Core,Ā .NET tool,Ā andĀ Azure DevOps extension for SonarQube (Server, Cloud)). The setup is slightly different for each variant (see theĀ SonarScanner for .NETĀ andĀ Azure DevOps extension for SonarQube ServerĀ sections for 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 begin step, add the appropriate parameter to specify the location of the coverage report file that will be produced.
  • Just after the build step but before the scanner end step, ensure that your test step 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 DevOps extension for SonarQube (Server, Cloud).

dotnet-coverage

This is a modern alternative to the Visual Studio Code Coverage provided by Microsoft (see below) 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-coverage

Using 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 section for information about this parameter). We use 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 the need for 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.CommandLineTools

Using 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 we specify the path to the reports usingĀ sonar.cs.dotcover.reportsPathsĀ because we are using dotCoverĀ (see the Test coverage parameters section for information about this parameter).

OpenCover

To useĀ OpenCoverĀ you must download it fromĀ hereĀ and unzip it in an appropriate directory, for example:Ā C:\tools\opencover

Using 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.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 we specify the path to the reports usingĀ sonar.cs.opencover.reportsPathsĀ because we are using OpenCoverĀ (see the Test coverage parameters section for information about this parameter).

Coverlet

To use Coverlet, you must install it as a global dotnet tool:

dotnet tool install --global coverlet.console

You also have to installĀ the coverlet collector NuGet packageĀ on your test project.

Using 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.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 we specify 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 section 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Ā Using the SonarScanner for .NETĀ for more information.

Extension for Azure Devops

Using the Extension for Azure DevOps 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 Server, the scannerĀ beginĀ step is handled by theĀ SonarQubePrepareĀ task, and the scannerĀ endĀ step is handled by theĀ SonarQubeAnalyzeĀ task.

Also note that because our build is running on Windows (we specifyĀ vmImage: windows-latest), we do not need to explicitly specify the path to the coverage report (there is noĀ sonar.cs.vscoveragexml.reportsPaths=coverage.xml) nor do you need to runĀ codecoverage.exeĀ to convert the report to XML.

azure-pipelines.yml
trigger:
- master

variables:
- name: system.debug
  value: true 

pool:
  vmImage: windows-latest

steps:
- task: DotNetCoreCLI@2
  inputs:
    command: 'restore'
    projects: 'my-project.sln'
    feedsToUse: 'select'

- task: SonarQubePrepare@7
  inputs:
    SonarQube: '<YourSonarqubeServerEndpoint>'
    scannerMode: 'dotnet'
    projectKey: '<YourProjectKey>'
    projectName: '<YourProjectName>'

- task: DotNetCoreCLI@2
  inputs:
    command: 'build'
    projects: 'my-project.sln'

- task: DotNetCoreCLI@2
  inputs:
    command: 'test'
    projects: 'tests/**/*.csproj'
    arguments: '--collect "Code Coverage"' # This is all you need to add!

- task: SonarQubeAnalyze@7

VB.NET

The examples above are all for C# projects. For VB.NET projects the setup is identical except that you would use these parametersĀ (see the Test coverage parameters section for information about these parameters):

  • sonar.vbnet.vscoveragexml.reportsPathsĀ for Visual Studio Code Coverage
  • sonar.vbnet.dotcover.reportsPathsĀ for dotCover
  • sonar.vbnet.opencover.reportsPathsĀ for OpenCover or Coverlet

The parameterĀ sonar.cs.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

Using the UserSourceLink option of your tool generates the coverage report using source link URIs instead of system paths. You might need to turn off this option to use system paths as source input for file coverage.

Test coverage parameters.


Was this page helpful?

Ā© 2008-2025 SonarSource SA. All rights reserved. SONAR, SONARSOURCE, SONARQUBE, and CLEAN AS YOU CODE are trademarks of SonarSource SA.

Creative Commons License