Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save rszuban/b6853b61e8b319e95577258e846aebce to your computer and use it in GitHub Desktop.
Save rszuban/b6853b61e8b319e95577258e846aebce to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment