How to get Code Coverage showing in Sonar Cloud

Josh Dadak
Purplebricks Digital
4 min readApr 4, 2020

--

Josh Dadak | Tech Lead at Purplebricks

Edit: 30.10.2020 — So a while back I figured out how to do this without the Powershell, and I’ve updated as appropriate, key changes are in the yaml example.

So, recently Purplebricks bought into SonarCloud, which was great news. I had the task of integrating this into the build pipelines for my squads projects. It was really simple…though it took me hours of pulling my hair out to solve how to get code coverage showing. I felt like I could have done with an easy, ‘how-to’ guide, so once I’d figured out a way, I decided to write one in case other people were in the same boat.

First up we need to create a new project on Sonar.

At the top right, next to your profile picture is the + button. Press this and hit analyse new project.

Sonar Cloud Dashboard

Setting up a new project is pretty simple, you just need to fill in a few fields:

Creating a new project on SonarCloud

The important one to note down here is the project key, we’re going to need this to put in our build pipelines later on. Personally, I use a project key that matches the name of the service I’m analyzing. Once you’ve noted this down it’s time to head over to your code.

Next in my projects I wanted analyzing, I needed to add a unique project guid to each .csproj. This solved an issue where, when the next test project was built and run, the code coverage files generated would overwrite those from the previous test project. Therefore the results shown in Sonar would only represent the last test project ran. This is simple to do, generate a new guid (There’s several sites that can generate these for you) and add the following element to your .csproj.

<ProjectGuid>{181eab94-7e4e-4d45-8db7-7030efd1a50b}</ProjectGuid>

The last thing you need to add to your test projects are these packages:

<PackageReference Include="OpenCover" Version="4.7.922" />
<PackageReference Include="coverlet.msbuild" Version="2.7.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>

I needed to add these because dotnet test creates code coverage files in a certain format that Sonar Cloud does not understand; coverlet can create the coverage files in a format that Sonar can understand.

Once you’ve added these things to each of your test projects, it’s time to update our builds.

We use yaml files for our builds. This allows us to check our builds in with our code and have them source controlled. By Adding Sonar to the yaml, we can run the analysis as part of our continuous integration process and only allow the code to be merged in if it passes the Build Quality Gates reported by Sonar. This is what my yaml looks like; please note I’ve taken some steps out to keep it as brief as possible:

Medium doesn’t do syntax highlighting so here is a nice gist: https://gist.github.com/Bigtalljosh/d9836612abdb884de61d9736a370f37f

pool:
name: Azure Pipelines
variables:
BuildConfiguration: ‘Release’
ShortVersion: ‘1.0.0’
steps:
- task: SonarSource.sonarcloud.14d9cde6-c1da-4d55-aa01–2965cd301255.SonarCloudPrepare@1
displayName: ‘Prepare analysis on SonarCloud’
inputs:
SonarCloud: ‘My Project’
organization: MyOrganisation
projectKey: ‘testproject’
projectName: ‘My Project’
extraProperties: |
sonar.exclusions=**/obj/**,**/*.dll
sonar.cs.xunit.reportsPaths=${Agent.TempDirectory}/**/XUnit.TestResults.xml
sonar.cs.opencover.reportsPaths=${Agent.TempDirectory}/**/opencoverCoverage.xml
- task: DotNetCoreCLI@2
displayName: Restore
inputs:
command: restore
projects: ‘**/*.csproj’
noCache: true
- task: DotNetCoreCLI@2
displayName: Build
inputs:
projects: ‘**/*.csproj’
arguments: ‘ — configuration $(BuildConfiguration) /property:Version=$(ShortVersion) — no-restore’
- task: DotNetCoreCLI@2
displayName: Test
inputs:
command: test
projects: ‘**/*.Tests.csproj’
arguments: '--configuration $(BuildConfiguration) --no-build /p:CollectCoverage=true /p:CoverletOutputFormat=opencover /p:CoverletOutput=$(Agent.TempDirectory)/coverage/ /p:MergeWith=$(Agent.TempDirectory)/coverage/ --collect "Code coverage"'
- task: PublishTestResults@2
displayName: "Publish Test Results"
inputs:
testResultsFormat: VSTest
testResultsFiles: "$(Agent.TempDirectory)/**.*trx"
mergeTestResults: true
condition: succeededOrFailed()
- task: SonarSource.sonarcloud.ce096e50–6155–4de8–8800–4221aaeed4a1.SonarCloudAnalyze@1
displayName: ‘Run Code Analysis’
- task: SonarSource.sonarcloud.38b27399-a642–40af-bb7d-9971f69712e8.SonarCloudPublish@1
displayName: ‘Publish Quality Gate Result’
#I would then package and publish the app

The key things to note here are the first task Prepare analysis on SonarCloud; in here you can see we use the project key we made a note of right at the start. This step also needs to come before any of the others. The other steps Run Code Analysis, need to come after the testing is done, and Publish Quality Gate Result is optional. However, this is the step that will allow us to determine if the build passed the quality gates we have set for this project.

Once you have these steps added to your own yaml, save all the files you’ve changed, then commit, push and head over to Sonar to see the results.

You should no longer see this:

:(

Instead you should see something like this:

:)

I am currently working on a way to get the amount of tests to show, so watch this space for another article on that

Now to fix these other projects. . .

I hope this helps somebody. If you know a way to make this process simpler, or to get the number of tests showing, please leave a comment below! If there’s an appetite, I may also do a post on how to run this on a PR Build, so let me know.

--

--

Josh Dadak
Purplebricks Digital

Engineering Manager @ ASOS, Previously Tech Lead @ Purplebricks. Founder of Powered4TV. Developer, teacher, all around nerd.