Script generating a code coverage report with dotCover and later converting it with Report Generator so that Azure DevOps task Publish Code Coverage Results can use it.
#region Basic configuration variables | |
# Comment out or remove $dotnetExecutable or $vsTestExecutable depending on needs. | |
# Adjust paths so that they lead to executables on a build server. | |
$dotCoverExecutable = 'C:\Program Files\DotCover\dotCover.exe' | |
$dotnetExecutable = 'C:\Program Files\dotnet\dotnet.exe' | |
$vsTestExecutable = 'C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\Common7\IDE\Extensions\TestPlatform\vstest.console.exe' | |
$reportGeneratorExecutable = 'C:\Windows\ServiceProfiles\NetworkService\.dotnet\tools\reportgenerator.exe' | |
# This pattern will be used to identify test projects. Use array if necessary. | |
$testProjectPattern = '*Tests.csproj' | |
# For more info on dotCover assembly filter visit: | |
# https://www.jetbrains.com/help/dotcover/Running_Coverage_Analysis_from_the_Command_LIne.html#filters. | |
$dotCoverAssemblyFilter = '+:Module=MyApplication*;' | |
#endregion | |
#region Checks if paths to executables are correct | |
# If you commented or removed any executable paths do the same for apropriate check. | |
if (-not (Test-Path -Path $dotcoverExecutable)) { | |
Throw "Path to DotCover executable is not correct." | |
} | |
if (-not (Test-Path -Path $dotnetExecutable)) { | |
Throw "Path to dotnet executable is not correct." | |
} | |
if (-not (Test-Path -Path $vsTestExecutable)) { | |
Throw "Path to vsTest executable is not correct." | |
} | |
if (-not (Test-Path -Path $reportGeneratorExecutable)) { | |
Throw "Path to Report Generator executable is not correct." | |
} | |
#endregion | |
# If necessary use -Exclude parameter to get full benefits of Get-ChildItem | |
$testProjectsArguments = @{ | |
Path = "$(System.DefaultWorkingDirectory)" | |
Include = $testProjectPattern | |
} | |
$testProjects = Get-ChildItem @testProjectsArguments -Recurse -File | |
if ($testProjects.count -eq 0) { | |
throw "No files matched the $testProjectPattern pattern. The script cannot continue." | |
} | |
#region Directory structure creation | |
<# | |
The script will create the following directory structure. | |
$(System.DefaultWorkingDirectory) | |
└──coverage-report/ | |
├── cobertura/ | |
└── html/ | |
#> | |
$reportDirectory = Join-Path -Path "$(System.DefaultWorkingDirectory)" -ChildPath "coverage-report" | |
if (Test-Path -Path $reportDirectory) { | |
Remove-Item -Path ( Join-Path -Path $reportDirectory -ChildPath "*" ) -Recurse | |
} | |
else { | |
New-Item -Path $reportDirectory -ItemType Directory | |
} | |
$reportDirectoryCobertura = Join-Path -Path $reportDirectory -ChildPath "cobertura" | |
New-Item -Path $reportDirectoryCobertura -ItemType Directory | |
$reportDirectoryHtml = Join-Path -Path $reportDirectory -ChildPath "html" | |
New-Item -Path $reportDirectoryHtml -ItemType Directory | |
#endregion | |
#region Test coverage with DotCover | |
foreach ($testProject in $testProjects) { | |
$reportOutputPathArguments = @{ | |
Path = $reportDirectory | |
ChildPath = "$( $testProject.BaseName )_coverage.xml" | |
} | |
$reportOutputPath = Join-Path @reportOutputPathArguments | |
# Again depending on needs remove or comment out unnecessary region below | |
#region Arguments and dotCover execution for dotnet | |
# CoreInstructionSet is handy when launching dotCover as a service account. | |
# Set its value to either x86 or x64 depending on project bitness | |
$dotCoverDotnetArguments = @( | |
"cover", | |
"/TargetExecutable=$dotnetExecutable", | |
"/TargetArguments=test $( $testProject.FullName ) --configuration=$(BuildConfiguration)", | |
"/Output=$reportOutputPath", | |
"/ReportType=DetailedXML", | |
"/Filters=$dotCoverAssemblyFilter" | |
"/CoreInstructionSet=x64" | |
) | |
Write-Output "Executing DotCover with following arguments: $dotCoverDotnetArguments." | |
& "$dotCoverExecutable" @dotCoverDotnetArguments | |
#endregion | |
#region Arguments and dotCover execution with vsTest | |
# In case of VsTest the test projects needs to be built before execution of this scrip. | |
# The dll file containing tests assemblies needs to be found. | |
$testProjectDllArguments = @{ | |
Path = Join-Path -Path "$( $testProject.DirectoryName )" -ChildPath "\bin\$(BuildConfiguration)" | |
Include = "$( $testProject.BaseName ).dll" | |
} | |
$testProjectDll = Get-ChildItem @testProjectDllArguments -Recurse -File | |
if ($testProjectDll.Count -ne 1) { | |
Throw "Make sure that tests projects are built before running this script." | |
} | |
# CoreInstructionSet is handy when launching dotCover as a service account. | |
# Set its value to either x86 or x64 depending on project bitness | |
$dotCoverVsTestArguments = @( | |
"cover", | |
"/TargetExecutable=$vsTestExecutable", | |
"/TargetArguments=$( $testProjectDll.FullName )", | |
"/Output=$reportOutputPath", | |
"/ReportType=DetailedXML", | |
"/Filters=$dotCoverAssemblyFilter", | |
"/CoreInstructionSet=x64" | |
) | |
Write-Output "Executing DotCover with following arguments: $dotCoverVsTestArguments." | |
& "$dotCoverExecutable" @dotCoverVsTestArguments | |
#endregion | |
if ( -not $? ) { | |
Throw "At least one unit test haven't passed. The script cannot continue." | |
} | |
} | |
#endregion | |
# region Generating reports in html and Cobertura format | |
$coverageReports = Get-ChildItem -Path $reportDirectory -Include '*_coverage.xml' -File -Recurse | |
if ($coverageReports.Count -eq 0) { | |
Throw "No coverage reports were generated. The script cannot continue." | |
} | |
$reportsFilePaths = $coverageReports.FullName -join ';' | |
$reportGeneratorCoberturaParams = @( | |
"-reports: $reportsFilePaths", | |
"-targetdir:$reportDirectoryCobertura", | |
"-reporttypes:Cobertura" | |
) | |
Write-Output "Executing Report Generator with following parameters: $reportGeneratorCoberturaParams." | |
& "$reportGeneratorExecutable" @reportGeneratorCoberturaParams | |
$reportGeneratorHtmlParams = @( | |
"-reports:$reportsFilePaths", | |
"-targetdir:$reportDirectoryHtml", | |
"-reporttypes:HtmlInline_AzurePipelines" | |
) | |
Write-Output "Executing Report Generator with following parameters: $reportGeneratorHtmlParams." | |
& "$reportGeneratorExecutable" @reportGeneratorHtmlParams |
I’m a DevOps/SRE/DevSecOps/Cloud Expert passionate about sharing knowledge and experiences. I am working at Cotocus. I blog tech insights at DevOps School, travel stories at Holiday Landmark, stock market tips at Stocks Mantra, health and fitness guidance at My Medic Plus, product reviews at I reviewed , and SEO strategies at Wizbrand.
Please find my social handles as below;
Rajesh Kumar Personal Website
Rajesh Kumar at YOUTUBE
Rajesh Kumar at INSTAGRAM
Rajesh Kumar at X
Rajesh Kumar at FACEBOOK
Rajesh Kumar at LINKEDIN
Rajesh Kumar at PINTEREST
Rajesh Kumar at QUORA
Rajesh Kumar at WIZBRAND