Skip to content

Commit

Permalink
Add TestsResult parameter to use existing tests results for the overa…
Browse files Browse the repository at this point in the history
…ll test-related metrics
  • Loading branch information
MathieuBuisson committed May 6, 2017
1 parent 70c0873 commit 66109d6
Show file tree
Hide file tree
Showing 8 changed files with 181 additions and 19 deletions.
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Get-FunctionDefinition.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Function Get-FunctionDefinition {
[OutputType([System.Management.Automation.Language.FunctionDefinitionAst[]])]
Param (
[Parameter(Position=0, Mandatory=$True, ValueFromPipeline=$True)]
[validatescript({ Test-Path $_ -PathType Leaf })]
[ValidateScript({ Test-Path $_ -PathType Leaf })]
[string[]]$Path
)
Process {
Expand Down
8 changes: 4 additions & 4 deletions PSCodeHealth/Private/Get-FunctionTestCoverage.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Function Get-FunctionTestCoverage {
[System.Management.Automation.Language.FunctionDefinitionAst]$FunctionDefinition,

[Parameter(Position=1, Mandatory=$False)]
[validatescript({ Test-Path $_ })]
[ValidateScript({ Test-Path $_ })]
[string]$TestsPath
)

Expand All @@ -45,10 +45,10 @@ Function Get-FunctionTestCoverage {
$TestsPath = Split-Path -Path $SourcePath -Parent
}

$TestResult = Invoke-Pester -Script $TestsPath -CodeCoverage @{ Path = $SourcePath; Function = $FunctionName } -PassThru -Show None -Verbose:$False
$TestsResult = Invoke-Pester -Script $TestsPath -CodeCoverage @{ Path = $SourcePath; Function = $FunctionName } -PassThru -Show None -Verbose:$False

If ( $TestResult.CodeCoverage ) {
$CodeCoverage = $TestResult.CodeCoverage
If ( $TestsResult.CodeCoverage ) {
$CodeCoverage = $TestsResult.CodeCoverage
$CommandsFound = $CodeCoverage.NumberOfCommandsAnalyzed
Write-VerboseOutput -Message "Number of commands found in the function : $($CommandsFound)"

Expand Down
2 changes: 1 addition & 1 deletion PSCodeHealth/Private/Get-PowerShellFile.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ Function Get-PowerShellFile {

Param (
[Parameter(Position=0, Mandatory=$True, ValueFromPipeline=$True)]
[validatescript({ Test-Path $_ -PathType Container })]
[ValidateScript({ Test-Path $_ -PathType Container })]
[string]$Path,

[switch]$Recurse,
Expand Down
35 changes: 26 additions & 9 deletions PSCodeHealth/Private/New-PSCodeHealthReport.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,15 @@ Function New-PSCodeHealthReport {
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.
.PARAMETER TestsResult
To use an existing Pester tests result object for generating the following metrics :
- NumberOfTests
- NumberOfFailedTests
- NumberOfPassedTests
- TestsPassRate (%)
- TestCoverage (%)
- CommandsMissedTotal
.EXAMPLE
PS C:\> New-PSCodeHealthReport -Path $MyPath -FunctionHealthRecord $FunctionHealthRecords -TestsPath "$MyPath\Tests"
Expand All @@ -40,8 +49,11 @@ Function New-PSCodeHealthReport {
[PSCustomObject[]]$FunctionHealthRecord,

[Parameter(Position=2, Mandatory)]
[validatescript({ Test-Path $_ })]
[string]$TestsPath
[ValidateScript({ Test-Path $_ })]
[string]$TestsPath,

[Parameter(Position=3, Mandatory=$False)]
[PSCustomObject]$TestsResult
)

# Getting ScriptAnalyzer findings from PowerShell manifests or data files and adding them to the report
Expand All @@ -66,9 +78,14 @@ Function New-PSCodeHealthReport {
$ScriptAnalyzerInformation = $AllScriptAnalyzerResults | Where-Object Severity -EQ 'Information'

# Gettings overall test coverage for all code in $Path
$TestResult = Invoke-Pester -Script $TestsPath -CodeCoverage $Path -Show None -PassThru -Verbose:$False -WarningAction SilentlyContinue
If ( $TestResult.CodeCoverage ) {
$CodeCoverage = $TestResult.CodeCoverage
If ( ($PSBoundParameters.ContainsKey('TestsResult')) ) {
$TestsResult = $PSBoundParameters.TestsResult
}
Else {
$TestsResult = Invoke-Pester -Script $TestsPath -CodeCoverage $Path -Show None -PassThru -Verbose:$False -WarningAction SilentlyContinue
}
If ( $TestsResult.CodeCoverage ) {
$CodeCoverage = $TestsResult.CodeCoverage
$CommandsMissed = $CodeCoverage.NumberOfCommandsMissed
Write-VerboseOutput -Message "Number of commands found in the function : $($CommandsMissed)"

Expand Down Expand Up @@ -96,10 +113,10 @@ Function New-PSCodeHealthReport {
'ScriptAnalyzerWarnings' = ($ScriptAnalyzerWarnings | Measure-Object).Count
'ScriptAnalyzerInformation' = ($ScriptAnalyzerInformation | Measure-Object).Count
'ScriptAnalyzerFindingsAverage' = [math]::Round(($FunctionHealthRecord.ScriptAnalyzerFindings | Measure-Object -Average).Average, 2)
'NumberOfTests' = If ( $TestResult ) { $TestResult.TotalCount } Else { 0 }
'NumberOfFailedTests' = If ( $TestResult ) { $TestResult.FailedCount } Else { 0 }
'NumberOfPassedTests' = If ( $TestResult ) { $TestResult.PassedCount } Else { 0 }
'TestsPassRate' = If ($TestResult.TotalCount) { [math]::Round(($TestResult.PassedCount / $TestResult.TotalCount) * 100, 2) } Else { 0 }
'NumberOfTests' = If ( $TestsResult ) { $TestsResult.TotalCount } Else { 0 }
'NumberOfFailedTests' = If ( $TestsResult ) { $TestsResult.FailedCount } Else { 0 }
'NumberOfPassedTests' = If ( $TestsResult ) { $TestsResult.PassedCount } Else { 0 }
'TestsPassRate' = If ($TestsResult.TotalCount) { [math]::Round(($TestsResult.PassedCount / $TestsResult.TotalCount) * 100, 2) } Else { 0 }
'TestCoverage' = $CodeCoveragePerCent
'CommandsMissedTotal' = $CommandsMissed
'ComplexityAverage' = [math]::Round(($FunctionHealthRecord.Complexity | Measure-Object -Average).Average, 2)
Expand Down
34 changes: 31 additions & 3 deletions PSCodeHealth/Public/Invoke-PSCodeHealth.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ Function Invoke-PSCodeHealth {
To specify the file or directory where tests are located.
If not specified, the command will look for tests in the same directory as each function.
.PARAMETER TestsResult
To use an existing Pester tests result object for generating the following metrics :
- NumberOfTests
- NumberOfFailedTests
- NumberOfPassedTests
- TestsPassRate (%)
- TestCoverage (%)
- CommandsMissedTotal
.PARAMETER Recurse
To search PowerShell files in the Path directory and all subdirectories recursively.
Expand Down Expand Up @@ -50,13 +59,17 @@ Function Invoke-PSCodeHealth {
[OutputType([PSCustomObject])]
Param (
[Parameter(Position=0, Mandatory=$False, ValueFromPipeline=$True)]
[validatescript({ Test-Path $_ })]
[ValidateScript({ Test-Path $_ })]
[string]$Path,

[Parameter(Position=1, Mandatory=$False)]
[validatescript({ Test-Path $_ })]
[ValidateScript({ Test-Path $_ })]
[string]$TestsPath,

[Parameter(Position=2, Mandatory=$False)]
[ValidateScript({ $_.TotalCount -is [int] })]
[PSCustomObject]$TestsResult,

[switch]$Recurse,

[Parameter(Mandatory=$False)]
Expand Down Expand Up @@ -118,5 +131,20 @@ Function Invoke-PSCodeHealth {
$TestsPath = If ( (Get-Item -Path $Path).PSIsContainer ) { $Path } Else { Split-Path -Path $Path -Parent }
}

New-PSCodeHealthReport -Path $PowerShellFiles -FunctionHealthRecord $FunctionHealthRecords -TestsPath $TestsPath
If ( ($PSBoundParameters.ContainsKey('TestsResult')) ) {
$PSCodeHealthReportParams = @{
Path = $PowerShellFiles
FunctionHealthRecord = $FunctionHealthRecords
TestsPath = $TestsPath
TestsResult = $PSBoundParameters.TestsResult
}
}
Else {
$PSCodeHealthReportParams = @{
Path = $PowerShellFiles
FunctionHealthRecord = $FunctionHealthRecords
TestsPath = $TestsPath
}
}
New-PSCodeHealthReport @PSCodeHealthReportParams
}
56 changes: 56 additions & 0 deletions Tests/Unit/Private/New-PSCodeHealthReport.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -420,5 +420,61 @@ Describe 'New-PSCodeHealthReport' {
$Result.FunctionHealthRecords | Should BeNullOrEmpty
}
}
Context 'Invoke-Pester returns nothing at all, but the TestsResult parameter is used' {

$Psd1 = (Get-ChildItem -Path "$($PSScriptRoot)\..\TestData\ManifestWithFindings.psd1").FullName
$PesterResult = $Mocks.'Invoke-Pester'.'NumberOfTests' | Where-Object { $_ }
Mock Invoke-Pester { }
$Result = New-PSCodeHealthReport -Path $Psd1 -TestsPath $TestsPath -FunctionHealthRecord $Null -TestsResult $PesterResult

It 'Should return an object with the expected property "LinesOfCodeTotal"' {
$Result.LinesOfCodeTotal | Should Be 0
}
It 'Should return an object with the expected property "LinesOfCodeAverage"' {
$Result.LinesOfCodeAverage | Should Be 0
}
It 'Should return an object with the expected property "ScriptAnalyzerFindingsTotal"' {
$Result.ScriptAnalyzerFindingsTotal | Should Be 3
}
It 'Should return an object with the expected property "ScriptAnalyzerErrors"' {
$Result.ScriptAnalyzerErrors | Should Be 0
}
It 'Should return an object with the expected property "ScriptAnalyzerWarnings"' {
$Result.ScriptAnalyzerWarnings | Should Be 3
}
It 'Should return an object with the expected property "ScriptAnalyzerInformation"' {
$Result.ScriptAnalyzerInformation | Should Be 0
}
It 'Should return an object with the expected property "ScriptAnalyzerFindingsAverage"' {
$Result.ScriptAnalyzerFindingsAverage | Should Be 0
}
It 'Should return an object with the expected property "NumberOfTests"' {
$Result.NumberOfTests | Should Be 51
}
It 'Should return an object with the expected property "NumberOfFailedTests"' {
$Result.NumberOfFailedTests | Should Be 7
}
It 'Should return an object with the expected property "NumberOfPassedTests"' {
$Result.NumberOfPassedTests | Should Be 44
}
It 'Should return an object with the expected property "TestsPassRate"' {
$Result.TestsPassRate | Should Be 86.27
}
It 'Should return an object with the expected property "TestCoverage"' {
$Result.TestCoverage | Should Be 81.48
}
It 'Should return an object with the expected property "CommandsMissedTotal"' {
$Result.CommandsMissedTotal | Should Be 5
}
It 'Should return an object with the expected property "ComplexityAverage"' {
$Result.ComplexityAverage | Should Be 0
}
It 'Should return an object with the expected property "NestingDepthAverage"' {
$Result.NestingDepthAverage | Should Be 0
}
It 'Should not call Invoke-Pester' {
Assert-MockCalled Invoke-Pester -Scope Context -Times 0
}
}
}
}
55 changes: 55 additions & 0 deletions Tests/Unit/Public/Invoke-PSCodeHealth2.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Describe 'Invoke-PSCodeHealth (again)' {

InModuleScope $ModuleName {

$Mocks = ConvertFrom-Json (Get-Content -Path "$($PSScriptRoot)\..\TestData\MockObjects.json" -Raw )
Copy-Item -Path (Get-ChildItem -Path "$($PSScriptRoot)\..\TestData\" -Filter '*.psm1').FullName -Destination TestDrive:\

Context 'Get-PowerShellFile returns 2 files and TestsPath parameter is specified' {
Expand Down Expand Up @@ -176,5 +177,59 @@ Describe 'Invoke-PSCodeHealth (again)' {
Should Throw 'The current location is from the Registry provider, please provide a value for the Path parameter or change to a FileSystem location.'
}
}
Context 'The TestsResult parameter is specified' {

$PesterResult = $Mocks.'Invoke-Pester'.'NumberOfTests' | Where-Object { $_ }
$Result = Invoke-PSCodeHealth -Path "$TestDrive\2PublicFunctions.psm1" -TestsResult $PesterResult

It 'Should return an object with the expected property "LinesOfCodeTotal"' {
$Result.LinesOfCodeTotal | Should Be 31
}
It 'Should return an object with the expected property "LinesOfCodeAverage"' {
$Result.LinesOfCodeAverage | Should Be 15.5
}
It 'Should return an object with the expected property "ScriptAnalyzerFindingsTotal"' {
$Result.ScriptAnalyzerFindingsTotal | Should Be 1
}
It 'Should return an object with the expected property "ScriptAnalyzerErrors"' {
$Result.ScriptAnalyzerErrors | Should Be 0
}
It 'Should return an object with the expected property "ScriptAnalyzerWarnings"' {
$Result.ScriptAnalyzerWarnings | Should Be 1
}
It 'Should return an object with the expected property "ScriptAnalyzerInformation"' {
$Result.ScriptAnalyzerInformation | Should Be 0
}
It 'Should return an object with the expected property "ScriptAnalyzerFindingsAverage"' {
$Result.ScriptAnalyzerFindingsAverage | Should Be 0.5
}
It 'Should return an object with the expected property "NumberOfTests"' {
$Result.NumberOfTests | Should Be 51
}
It 'Should return an object with the expected property "NumberOfFailedTests"' {
$Result.NumberOfFailedTests | Should Be 7
}
It 'Should return an object with the expected property "NumberOfPassedTests"' {
$Result.NumberOfPassedTests | Should Be 44
}
It 'Should return an object with the expected property "TestsPassRate"' {
$Result.TestsPassRate | Should Be 86.27
}
It 'Should return an object with the expected property "TestCoverage"' {
$Result.TestCoverage | Should Be 81.48
}
It 'Should return an object with the expected property "CommandsMissedTotal"' {
$Result.CommandsMissedTotal | Should Be 5
}
It 'Should return an object with the expected property "ComplexityAverage"' {
$Result.ComplexityAverage | Should Be 1
}
It 'Should return an object with the expected property "NestingDepthAverage"' {
$Result.NestingDepthAverage | Should Be 1
}
It 'Should return 2 objects in the property "FunctionHealthRecords"' {
$Result.FunctionHealthRecords.Count | Should Be 2
}
}
}
}
8 changes: 7 additions & 1 deletion Tests/Unit/TestData/MockObjects.json
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,13 @@
"NumberOfCommandsAnalyzed": 27,
"NumberOfCommandsMissed": 5,
"NumberOfCommandsExecuted": 22
}
},
"Name": "MockResultName",
"Time": {
"TotalSeconds": 3
},
"FailureMessage": "MockFailureMessage",
"StackTrace": "MockStackTrace"
}
}
],
Expand Down

0 comments on commit 66109d6

Please sign in to comment.