Building on our previous post, we can take the coverage information generated by OpenCover and generate a report that shows us where our coverage is lacking.

We’ll use the ReportGenerator tool. In an approach that should be familiar by now, we start by adding a NuGet reference to the project and then writing a psake task that finds the report generator tool:

Task Requires.ReportGenerator {

    $script:reportGeneratorExe =
        resolve-path ".\packages\ReportGenerator.*\tools\ReportGenerator.exe"

    if ($reportGeneratorExe -eq $null)
        throw "Failed to find ReportGenerator.exe"

    Write-Host "Found Report Generator here: $reportGeneratorExe"

We need an empty folder for the coverage report, so we create one with a configuration task:

Task Configure.TestResultsFolder -Depends Requires.BuildDir {

    $script:testResultsFolder = join-path $buildDir testing.results
    Write-Host "Test results folder: $testResultsFolder"

    if (test-path $testResultsFolder) {
        remove-item $testResultsFolder -recurse -force -ErrorAction SilentlyContinue

    mkdir $testResultsFolder -ErrorAction SilentlyContinue | Out-Null

It’s worth noting that we try to remove the report target folder if it already exists, creating a new one each time - this is an easy way to try and ensure the file doesn’t contain any debris from the prior coverage report. By using -ErrorAction SilentlyContinue for both steps, we don’t abort the build if we can’t remove everything - keeping the directory tidy is helpful, but failing to do so shouldn’t be fatal. (I’ve found that sometimes, just sometimes, the script fails to remove one of the HTML files, perhaps because IIS still has the file open.)

Next, we write a Coverage.Report task that accumulates all the coverage reports generated by OpenCover and generates the report:

Task Coverage.Report -Depends Requires.ReportGenerator, Configure.OpenCoverReportFolder,
         Coverage.Tests {

    exec {
        & $reportGeneratorExe -reports:$testResultsFolder\*.opencover.xml

    $openCoverIndex = resolve-path $openCoverReportFolder\index.htm
    & $openCoverIndex

We use the wildcard *.opencover.xml to pick up all the coverage reports and ReportGenerator does the rest. We finish by automatically opening the report in the default browser - you may want to comment out this step if you find it distracting, or if you decide to include the coverage report in your continuous integration build.

The final result is a useful report. The front page summarizes the coverage achieved by our tests:

Even better, you can drill down to see more details of the test coverage, right down to the individual line of code:

Prior post in this series:
Test Coverage with Opencover
Next post in this series:
.NET Core Builds


blog comments powered by Disqus