Public/Test-PSBuildPester.ps1
function Test-PSBuildPester { <# .SYNOPSIS Execute Pester tests for module. .DESCRIPTION Execute Pester tests for module. .PARAMETER Path Directory Pester tests to execute. .PARAMETER ModuleName Name of Module to test. .PARAMETER ModuleManifest Path to module manifest to import during test .PARAMETER OutputPath Output path to store Pester test results to. .PARAMETER OutputFormat Test result output format (NUnit). .PARAMETER CodeCoverage Switch to indicate that code coverage should be calculated. .PARAMETER CodeCoverageThreshold Threshold required to pass code coverage test (.90 = 90%). .PARAMETER CodeCoverageFiles Array of files to validate code coverage for. .PARAMETER CodeCoverageOutputFile Output path (relative to Pester tests directory) to store code coverage results to. .PARAMETER CodeCoverageOutputFileFormat Code coverage result output format. Currently, only 'JaCoCo' is supported by Pester. .PARAMETER ImportModule Import module from OutDir prior to running Pester tests. .EXAMPLE PS> Test-PSBuildPester -Path ./tests -ModuleName Mymodule -OutputPath ./out/testResults.xml Run Pester tests in ./tests and save results to ./out/testResults.xml #> [cmdletbinding()] param( [parameter(Mandatory)] [string]$Path, [string]$ModuleName, [string]$ModuleManifest, [string]$OutputPath, [string]$OutputFormat = 'NUnit2.5', [switch]$CodeCoverage, [double]$CodeCoverageThreshold, [string[]]$CodeCoverageFiles = @(), [string]$CodeCoverageOutputFile = 'coverage.xml', [string]$CodeCoverageOutputFileFormat = 'JaCoCo', [switch]$ImportModule ) if (-not (Get-Module -Name Pester)) { Import-Module -Name Pester -ErrorAction Stop } try { if ($ImportModule) { if (-not (Test-Path $ModuleManifest)) { Write-Error "Unable to find module manifest [$ModuleManifest]. Can't import module" } else { # Remove any previously imported project modules and import from the output dir Get-Module $ModuleName | Remove-Module -Force -ErrorAction SilentlyContinue Import-Module $ModuleManifest -Force } } Push-Location -LiteralPath $Path Import-Module Pester -MinimumVersion 5.0.0 $configuration = [PesterConfiguration]::Default $configuration.Output.Verbosity = 'Detailed' $configuration.Run.PassThru = $false $configuration.TestResult.Enabled = -not [string]::IsNullOrEmpty($OutputPath) $configuration.TestResult.OutputPath = $OutputPath $configuration.TestResult.OutputFormat = $OutputFormat if ($CodeCoverage.IsPresent) { $configuration.CodeCoverage.Enabled = $true if ($CodeCoverageFiles.Count -gt 0) { $configuration.CodeCoverage.Path = $CodeCoverageFiles } $configuration.CodeCoverage.OutputPath = $CodeCoverageOutputFile $configuration.CodeCoverage.OutputFormat = $CodeCoverageOutputFileFormat } $testResult = Invoke-Pester -Configuration $configuration -Verbose:$VerbosePreference if ($testResult.FailedCount -gt 0) { throw 'One or more Pester tests failed' } if ($CodeCoverage.IsPresent) { Write-Host "`nCode Coverage:`n" -ForegroundColor Yellow if (Test-Path $CodeCoverageOutputFile) { $textInfo = (Get-Culture).TextInfo [xml]$testCoverage = Get-Content $CodeCoverageOutputFile $ccReport = $testCoverage.report.counter.ForEach({ $total = [int]$_.missed + [int]$_.covered $perc = [Math]::Truncate([int]$_.covered / $total) [pscustomobject]@{ name = $textInfo.ToTitleCase($_.Type.ToLower()) percent = $perc } }) $ccFailMsgs = @() $ccReport.ForEach({ 'Type: [{0}]: {1:p}' -f $_.name, $_.percent if ($_.percent -lt $CodeCoverageThreshold) { $ccFailMsgs += ('Code coverage: [{0}] is [{1:p}], which is less than the threshold of [{2:p}]' -f $_.name, $_.percent, $CodeCoverageThreshold) } }) Write-Host "`n" $ccFailMsgs.Foreach({ Write-Error $_ }) } else { Write-Error "Code coverage file [$CodeCoverageOutputFile] not found." } } } finally { Pop-Location Remove-Module $ModuleName -ErrorAction SilentlyContinue } } |