Private/Metrics/Get-FunctionTestCoverage.ps1
Function Get-FunctionTestCoverage { <# .SYNOPSIS Gets test coverage information for the specified function. .DESCRIPTION Gets test coverage information for the specified function. This includes 2 pieces of information : - Code coverage percentage (lines of code that are exercized by unit tests) - Missed Commands (lines of codes or commands not being exercized by unit tests) It uses Pester with its CodeCoverage parameter. .PARAMETER FunctionDefinition To specify the function definition to analyze. .PARAMETER TestsPath To specify the file or directory where the Pester tests are located. If a directory is specified, the directory and all subdirectories will be searched recursively for tests. If not specified, the directory of the file containing the specified function, and all subdirectories will be searched for tests. .EXAMPLE PS C:\> Get-FunctionTestCoverage -FunctionDefinition $MyFunctionAst -TestsPath $MyModule.ModuleBase Gets test coverage information for the function $MyFunctionAst given the tests found in the module's parent directory. .OUTPUTS PSCodeHealth.Function.TestCoverageInfo .NOTES #> [CmdletBinding()] [OutputType([PSCustomObject])] Param ( [Parameter(Position=0, Mandatory)] [System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition, [Parameter(Position=1, Mandatory=$False)] [ValidateScript({ Test-Path $_ })] [string]$TestsPath ) [string]$SourcePath = $FunctionDefinition.Extent.File $FunctionName = $FunctionDefinition.Name Write-VerboseOutput -Message "The function [$FunctionName] comes from the file : $SourcePath" If ( -not $TestsPath ) { $TestsPath = Split-Path -Path $SourcePath -Parent } # Invoke-Pester didn't have the "Show" parameter prior to version 4.x $SuppressOutput = If ((Get-Module -Name Pester).Version.Major -lt 4) { @{Quiet = $True} } Else { @{Show = 'None'} } $TestsResult = Invoke-Pester -Script $TestsPath -CodeCoverage @{ Path = $SourcePath; Function = $FunctionName } -PassThru -Verbose:$False @SuppressOutput If ( $TestsResult.CodeCoverage ) { $CodeCoverage = $TestsResult.CodeCoverage $CommandsFound = $CodeCoverage.NumberOfCommandsAnalyzed Write-VerboseOutput -Message "Number of commands found in the function : $($CommandsFound)" # To prevent any "Attempted to divide by zero" exceptions If ( $CommandsFound -ne 0 ) { $Commandsexercised = $CodeCoverage.NumberOfCommandsExecuted Write-VerboseOutput -Message "Number of commands exercized in the tests : $($CommandsExercised)" [System.Double]$CodeCoveragePerCent = [math]::Round(($CommandsExercised / $CommandsFound) * 100, 2) } Else { [System.Double]$CodeCoveragePerCent = 0 } $ObjectProperties = [ordered]@{ 'CodeCoveragePerCent' = $CodeCoveragePerCent 'CommandsMissed' = $CodeCoverage.MissedCommands } $CustomObject = New-Object -TypeName PSObject -Property $ObjectProperties $CustomObject.psobject.TypeNames.Insert(0, 'PSCodeHealth.Function.TestCoverageInfo') return $CustomObject } } |