In this post, I’m creating a code coverage report for a .NET Core project. I’m also using SonarCloud to analyze the project’s quality.
First things first. Code coverage should be something provided for free and out of the box. It should be easy to setup and something that just works. Unfortunately, that’s not the case for .NET Core. For the time being, you can only get code coverage either by using Visual Studio Enterprise (which is not free) or by using the open source tool OpenCover (which is Windows only). .NET Core is supposed to be a cross-platform solution and code coverage should also be available cross-platform. I hope this gets addressed in the near future. There is a GitHub issue which is still open.
My setup
- Windows 10 Home
- Visual Studio 2017 Community
- NuGet on the path
Generating code coverage report
To generate the code coverage report, I used OpenCover and ReportGenerator. The first tool does the heavy lifting of instrumenting the code. The latter generates a friendly HTML report. I have a PowerShell script for generating the report:
nuget install OpenCover -Version 4.6.519 -OutputDirectory packages
nuget install ReportGenerator -Version 3.1.2 -OutputDirectory packages
.\packages\OpenCover.4.6.519\tools\OpenCover.Console.exe `
-oldstyle `
-output:opencover.xml `
-register:user `
-filter:"+[MyApp*]* -[*.UnitTests]*" `
-target:"C:\Program Files\dotnet\dotnet.exe" `
-targetargs:"test --no-build MyApp.UnitTests"
.\packages\ReportGenerator.3.1.2\tools\ReportGenerator.exe `
-reports:opencover.xml `
-targetdir:coverage
Some points about this script:
- the
-target
andtargetargs
parameters specify the command that will run the unit tests. Combined, that'sdotnet test --no-build MyApp.UnitTests
. The--no-build
avoids rebuilding the project, assuming we've already built it. - the
-filter
argument is used to exclude the unit tests themselves from the coverage report. The unit test code shouldn't be part of the coverage report because then the numbers get inflated. - the
-register:user
allows this to work without administrator privileges. - the
-oldstyle
parameter is needed for .NET Core. - the
.csproj
files need to have full debug information. That's done with theDebugType
property.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<IsPackable>false</IsPackable>
<DebugType>Full</DebugType>
</PropertyGroup>
</Project>
OpenCover will generate an XML file at opencover.xml
and then ReportGenerator will produce the HTML report at the coverage
folder.
Analyzing code quality with SonarCloud
I discovered the other day that it’s possible to use SonarQube online for free for open source projects via a service called SonarCloud.
It’s possible to sign in with your GitHub account, as it’s expected for this type of tools, like Travis, Coveralls, etc. I’ve set it up just for the same .NET Core project, as an experiment.
To use SonarCloud, you need to download the SonarQube scanner for MSBuild.
The usage involves three steps:
- starting the scanner
- using MSBuild to build the project
- stopping the scanner and submitting the analysis to SonarCloud
I have a PowerShell script for that:
if (-Not ($Env:SONAR_LOGIN)) {
Write-Error -Category InvalidArgument -Message "Please set the SONAR_LOGIN environment variable"
Exit 1
}
SonarQube.Scanner.MSBuild.exe begin /k:"MyApp" `
/d:sonar.organization="ngeor-github" `
/d:sonar.host.url="https://sonarcloud.io" `
/d:sonar.login="$Env:SONAR_LOGIN" `
/d:sonar.cs.opencover.reportsPaths="opencover.xml" `
/d:sonar.coverage.exclusions="**/*Test.cs"
MSBuild.exe /t:Rebuild .\MyApp.sln
.\coverage.ps1
SonarQube.Scanner.MSBuild.exe end /d:sonar.login="$Env:SONAR_LOGIN"
Some comments on the script:
- the
SONAR_LOGIN
environment variable is my way of committing the script without committing the authorization token. You can get this token from SonarCloud. - you need to use an MSBuild that is compatible with .NET Core. In my case, that's the one that comes with Visual Studio 2017 (found at
C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\MSBuild\15.0\Bin
). - the SonarQube scanner supports OpenCover, so I'm also running my coverage script here.
The first analysis will take more time, subsequent runs are faster. In the end you get a nice dashboard:
And I see SonarCloud even supports various badges for your README: