From 3549f7a81533d062041bb10dc4a680bc5780a339 Mon Sep 17 00:00:00 2001 From: Chrissy LeMaire Date: Mon, 28 Oct 2024 11:31:14 +0100 Subject: [PATCH] Pester v5 runner fixes (#9533) --- .gitignore | 3 + private/testing/Invoke-ManualPester.ps1 | 347 +++++++++++++++--------- tests/Invoke-DbaQuery.Tests.ps1 | 42 ++- tests/appveyor.pester.ps1 | 21 +- 4 files changed, 260 insertions(+), 153 deletions(-) diff --git a/.gitignore b/.gitignore index 67a399dacf..fae081b550 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,9 @@ msbuild.binlog # Local constant file tests/constants.local.ps1 +# Local coverage file produced by pester5 +coverage.xml + # For those that want to use Docker images for testing # Integration with Docker requires the docker compose file to exist within the project folder docker-compose.yml diff --git a/private/testing/Invoke-ManualPester.ps1 b/private/testing/Invoke-ManualPester.ps1 index e8bf1d3513..0190d1cf74 100644 --- a/private/testing/Invoke-ManualPester.ps1 +++ b/private/testing/Invoke-ManualPester.ps1 @@ -57,7 +57,7 @@ function Invoke-ManualPester { Runs tests for all tests matching in `*orphan*.Tests.ps1 .EXAMPLE - Invoke-ManualPester -Path Find-DbaOrphanedFile.Tests.ps1 -Show Default + Invoke-ManualPester -Path Find-DbaOrphanedFile.Tests.ps1 -Show Normal Runs tests stored in Find-DbaOrphanedFile.Tests.ps1, with reduced verbosity @@ -89,174 +89,259 @@ function Invoke-ManualPester { [Parameter(Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('FullName')] [string[]]$Path, - [ValidateSet('None', 'Default', 'Passed', 'Failed', 'Pending', 'Skipped', 'Inconclusive', 'Describe', 'Context', 'Summary', 'Header', 'All', 'Fails')] - [string]$Show = "All", + [ValidateSet('None', 'Normal', 'Detailed', 'Diagnostic')] + [string]$Show = "Normal", [switch]$PassThru, [switch]$TestIntegration, [switch]$Coverage, [switch]$DependencyCoverage, [switch]$ScriptAnalyzer ) + begin { + Remove-Module -Name Pester + $stopProcess = $false + function Get-CoverageIndications($Path, $ModuleBase) { + # takes a test file path and figures out what to analyze for coverage (i.e. dependencies) + $CBHRex = [regex]'(?smi)<#(.*)#>' + $everything = (Get-Module dbatools).ExportedCommands.Values + $everyfunction = $everything.Name + $funcs = @() + $leaf = Split-Path $path -Leaf + # assuming Get-DbaFoo.Tests.ps1 wants coverage for "Get-DbaFoo" + # but allowing also Get-DbaFoo.one.Tests.ps1 and Get-DbaFoo.two.Tests.ps1 + $func_name += ($leaf -replace '^([^.]+)(.+)?.Tests.ps1', '$1') + if ($func_name -in $everyfunction) { + $funcs += $func_name + $f = $everything | Where-Object Name -eq $func_name + $source = $f.Definition + $CBH = $CBHRex.match($source).Value + $cmdonly = $source.Replace($CBH, '') + foreach ($e in $everyfunction) { + # hacky, I know, but every occurrence of any function plus a space kinda denotes usage !? + $searchme = "$e " + if ($cmdonly.contains($searchme)) { + $funcs += $e + } + } + } + $testpaths = @() + $allfiles = Get-ChildItem -File -Path "$ModuleBase\private\functions", "$ModuleBase\public" -Filter '*.ps1' + foreach ($f in $funcs) { + # exclude always used functions ?! + if ($f -in ('Connect-DbaInstance', 'Select-DefaultView', 'Stop-Function', 'Write-Message')) { continue } + # can I find a correspondence to a physical file (again, on the convenience of having Get-DbaFoo.ps1 actually defining Get-DbaFoo)? + $res = $allfiles | Where-Object { $_.Name.Replace('.ps1', '') -eq $f } + if ($res.count -gt 0) { + $testpaths += $res.FullName + } + } + return @() + ($testpaths | Select-Object -Unique) + } - $invokeFormatterVersion = (Get-Command Invoke-Formatter -ErrorAction SilentlyContinue).Version - $HasScriptAnalyzer = $null -ne $invokeFormatterVersion - $ScriptAnalyzerCorrectVersion = '1.18.2' - - if (!($HasScriptAnalyzer)) { - Write-Warning "Please install PSScriptAnalyzer" - Write-Warning " Install-Module -Name PSScriptAnalyzer -RequiredVersion '$ScriptAnalyzerCorrectVersion'" - Write-Warning " or go to https://github.com/PowerShell/PSScriptAnalyzer" - } else { - if ($invokeFormatterVersion -ne $ScriptAnalyzerCorrectVersion) { - Remove-Module PSScriptAnalyzer - try { - Import-Module PSScriptAnalyzer -RequiredVersion $ScriptAnalyzerCorrectVersion -ErrorAction Stop - } catch { - Write-Warning "Please install PSScriptAnalyzer $ScriptAnalyzerCorrectVersion" - Write-Warning " Install-Module -Name PSScriptAnalyzer -RequiredVersion '$ScriptAnalyzerCorrectVersion'" + function Get-PesterTestVersion($testFilePath) { + $testFileContent = Get-Content -Path $testFilePath -Raw + if ($testFileContent -match '#Requires\s+-Module\s+@\{\s+ModuleName="Pester";\s+ModuleVersion="5\.') + { + return '5' } + return '4' } - } - if ((Test-Path /workspace)) { - $ModuleBase = "/workspace" - } else { - $ModuleBase = Split-Path -Path $PSScriptRoot -Parent - } + # Go up the folder structure until we find the root of the module, where dbatools.psd1 is located + function Get-ModuleBase { + $startOfSearch = $PSScriptRoot + for ($i = 0; $i -lt 10; $i++) { + if (Test-Path (Join-Path $startOfSearch 'dbatools.psd1')) { + $ModuleBase = $startOfSearch + break + } + $startOfSearch = Split-Path -Path $startOfSearch -Parent + } + return $ModuleBase + } - if (-not(Test-Path "$ModuleBase\.git" -Type Container)) { - New-Item -Type Container -Path "$ModuleBase\.git" -Force - } + function Write-DetailedMessage($message) { + if ($Show -in @('Normal', 'Detailed', 'Diagnostic')) { + Write-Host -Object $message + } + } - # Remove-Module dbatools -ErrorAction Ignore - # Import-Module "$ModuleBase\dbatools.psd1" -DisableNameChecking -Force - $splatImport = @{ - Name = "$ModuleBase\dbatools.psm1" - DisableNameChecking = $true - Force = $true - WarningAction = 'Ignore' - ErrorAction = 'Ignore' - } - Import-Module @splatImport + $invokeFormatterVersion = (Get-Command Invoke-Formatter -ErrorAction SilentlyContinue).Version + $HasScriptAnalyzer = $null -ne $invokeFormatterVersion + $MinimumPesterVersion = [Version] '4.0.0.0' # Because this is when -Show was introduced + $MaximumPesterVersion = [Version] '6.0.0.0' # Because we have either pester4 or pester5 tests + $PesterVersion = (Get-Command Invoke-Pester -ErrorAction SilentlyContinue).Version + $HasPester = $null -ne $PesterVersion + $ScriptAnalyzerCorrectVersion = '1.18.2' + + if (!($HasScriptAnalyzer)) { + Write-Warning "Please install PSScriptAnalyzer" + Write-Warning " Install-Module -Name PSScriptAnalyzer -RequiredVersion '$ScriptAnalyzerCorrectVersion'" + Write-Warning " or go to https://github.com/PowerShell/PSScriptAnalyzer" + } else { + if ($invokeFormatterVersion -ne $ScriptAnalyzerCorrectVersion) { + Remove-Module PSScriptAnalyzer + try { + Import-Module PSScriptAnalyzer -RequiredVersion $ScriptAnalyzerCorrectVersion -ErrorAction Stop + } catch { + Write-Warning "Please install PSScriptAnalyzer $ScriptAnalyzerCorrectVersion" + Write-Warning " Install-Module -Name PSScriptAnalyzer -RequiredVersion '$ScriptAnalyzerCorrectVersion'" + } + } + } + + if (!($HasPester)) { + Write-Warning "Please install Pester" + Write-Warning " Install-Module -Name Pester -Force -SkipPublisherCheck" + Write-Warning " or go to https://github.com/pester/Pester" + } + if ($PesterVersion -lt $MinimumPesterVersion) { + Write-Warning "Please update Pester to at least 3.4.5" + Write-Warning " Install-Module -Name Pester -MaximumVersion '4.10' -Force -SkipPublisherCheck" + Write-Warning " or go to https://github.com/pester/Pester" + } + if ($PesterVersion -gt $MaximumPesterVersion) { + Write-Warning "Please get Pester to the 5.* release" + Write-Warning " Install-Module -Name Pester -MaximumVersion '5.6.1' -Force -SkipPublisherCheck" + Write-Warning " or go to https://github.com/pester/Pester" + } + + if (($HasPester -and $HasScriptAnalyzer -and ($PesterVersion -ge $MinimumPesterVersion) -and ($PesterVersion -lt $MaximumPesterVersion) -and ($invokeFormatterVersion -eq $ScriptAnalyzerCorrectVersion)) -eq $false) { + Write-Warning "Exiting..." + $stopProcess = $true + } - $ScriptAnalyzerRulesExclude = @('PSUseOutputTypeCorrectly', 'PSAvoidUsingPlainTextForPassword', 'PSUseBOMForUnicodeEncodedFile') - $testInt = $false - if ($config_TestIntegration) { - $testInt = $true - } - if ($TestIntegration) { - $testInt = $true - } - # Keep the Get-CoverageIndications function as is - function Get-CoverageIndications($Path, $ModuleBase) { - # [Previous implementation remains the same] } + process { + if ($stopProcess) { + return + } + + + $ModuleBase = Get-ModuleBase - function Get-PesterTestVersion($testFilePath) { - $testFileContent = Get-Content -Path $testFilePath -Raw - if ($testFileContent -match '#Requires\s+-Module\s+@\{\s+ModuleName="Pester";\s+ModuleVersion="5\.') { - return '5' + $gitPath = Join-Path $ModuleBase '.git' + if (-not(Test-Path $gitPath -Type Container)) { + $null = New-Item -Type Container -Path $gitPath -Force + } + + #removes previously imported dbatools, if any + # No need the force will do it + #Remove-Module dbatools -ErrorAction Ignore + #imports the module making sure DLL is loaded ok + Write-DetailedMessage "Importing dbatools psd1" + Import-Module "$ModuleBase\dbatools.psd1" -DisableNameChecking -Force -NoClobber + #imports the psm1 to be able to use internal functions in tests + Write-DetailedMessage "Importing dbatools psm1" + Import-Module "$ModuleBase\dbatools.psm1" -DisableNameChecking -Force -NoClobber + + $ScriptAnalyzerRulesExclude = @('PSUseOutputTypeCorrectly', 'PSAvoidUsingPlainTextForPassword', 'PSUseBOMForUnicodeEncodedFile') + + $testInt = $false + if ($config_TestIntegration) { + $testInt = $true + } + if ($TestIntegration) { + $testInt = $true } - return '4' - } - $files = @() + $files = @() - if ($Path) { - foreach ($item in $path) { - if (Test-Path $item) { - $files += Get-ChildItem -Path $item - } else { - $files += Get-ChildItem -Path "$ModuleBase\tests\*$item*.Tests.ps1" + if ($Path) { + foreach ($item in $path) { + if (Test-Path $item) { + $files += Get-ChildItem -Path $item + } else { + $files += Get-ChildItem -Path "$ModuleBase\tests\*$item*.Tests.ps1" + } } } - } - if ($files.Length -eq 0) { - Write-Warning "No tests to be run" - return - } + if ($files.Length -eq 0) { + Write-Warning "No tests to be run" + } - foreach ($f in $files) { - $pesterVersion = Get-PesterTestVersion -testFilePath $f.FullName - - # Remove any previously loaded pester module - Remove-Module -Name pester -ErrorAction SilentlyContinue - - if ($pesterVersion -eq '5') { - Import-Module Pester -RequiredVersion 5.6.1 - $pester5Config = New-PesterConfiguration - $pester5Config.Run.Path = $f.FullName - - # Convert SwitchParameter to bool for PassThru - $pester5Config.Run.PassThru = [bool]$PassThru - - # Convert Show parameter to v5 verbosity - $verbosityMap = @{ - 'None' = 'None' - 'Default' = 'Normal' - 'All' = 'Detailed' - 'Fails' = 'Detailed' - 'Describe' = 'Detailed' - 'Context' = 'Detailed' - 'Summary' = 'Normal' - 'Header' = 'Normal' - 'Passed' = 'Detailed' - 'Failed' = 'Detailed' - 'Pending' = 'Detailed' - 'Skipped' = 'Detailed' - 'Inconclusive' = 'Detailed' - } + $AllTestsWithinScenario = $files - $pester5Config.Output.Verbosity = $verbosityMap[$Show] - if (!($testInt)) { - $pester5Config.Filter.ExcludeTag = @('IntegrationTests') - } - if ($Coverage) { + foreach ($f in $AllTestsWithinScenario) { + $pesterVersionToUse = Get-PesterTestVersion -testFilePath $f.FullName + + #opt-in + $HeadFunctionPath = $f.FullName + + if ($Coverage -or $ScriptAnalyzer) { + Write-DetailedMessage "Getting coverage indications for $f" $CoverFiles = Get-CoverageIndications -Path $f -ModuleBase $ModuleBase - if (!$DependencyCoverage) { - $CoverFiles = $CoverFiles | Select-Object -First 1 - } - $pester5Config.CodeCoverage.Enabled = $true - $pester5Config.CodeCoverage.Path = $CoverFiles - $pester5Config.CodeCoverage.OutputFormat = 'JaCoCo' - $pester5Config.CodeCoverage.OutputPath = "$ModuleBase\Pester5Coverage.xml" - } + $HeadFunctionPath = $CoverFiles | Select-Object -First 1 - Invoke-Pester -Configuration $pester5Config - } else { - Import-Module pester -RequiredVersion 4.4.2 - $PesterSplat = @{ - 'Script' = $f.FullName - 'Show' = $show - 'PassThru' = $PassThru } - if ($Coverage) { - $CoverFiles = Get-CoverageIndications -Path $f -ModuleBase $ModuleBase - if (!$DependencyCoverage) { - $CoverFiles = $CoverFiles | Select-Object -First 1 + if ($DependencyCoverage) { + $CoverFilesPester = $CoverFiles + Write-DetailedMessage "We're going to target these files for coverage:" + foreach ($cf in $CoverFiles) { + Write-DetailedMessage "$cf" + } + } else { + $CoverFilesPester = $HeadFunctionPath } - $PesterSplat['CodeCoverage'] = $CoverFiles } - if (!($testInt)) { - $PesterSplat['ExcludeTag'] = "IntegrationTests" + if ($pesterVersionToUse -eq '5') { + Write-DetailedMessage "Running Pester 5 tests $($f.Name)" + Remove-Module -Name pester -ErrorAction SilentlyContinue + Import-Module pester -MinimumVersion 5.6.1 -ErrorAction Stop + $pester5Config = New-PesterConfiguration + $pester5Config.Run.Path = $f.FullName + if ($PassThru){ + $pester5config.Run.PassThru = $passThru + } + $pester5config.Output.Verbosity = $show + if ($Coverage) { + $pester5Config.CodeCoverage.Enabled = $true + $pester5Config.CodeCoverage.Path = $CoverFilesPester + } + if (!($testInt)) { + $pester5Config.Filter.ExcludeTag = "IntegrationTests" + } + Invoke-Pester -Configuration $pester5config + } + else { + Write-DetailedMessage "Running Pester 4 tests $($f.FullName)" + $pester4Show = 'Default' + switch ($Show) { + 'None' { $pester4Show = 'None' } + 'Normal' { $pester4Show = 'Default' } + 'Detailed' { $pester4Show = 'All' } + 'Diagnostic' { $pester4Show = 'All' } + } + $PesterSplat = @{ + 'Script' = $f.FullName + 'Show' = $pester4Show + 'PassThru' = $passThru + } + if ($Coverage) + { + $PesterSplat['CodeCoverage'] = $CoverFilesPester + } + if (!($testInt)) { + $PesterSplat['ExcludeTag'] = "IntegrationTests" + } + Invoke-Pester @PesterSplat } - Invoke-Pester @PesterSplat - } - if ($ScriptAnalyzer) { - $HeadFunctionPath = (Get-CoverageIndications -Path $f -ModuleBase $ModuleBase | Select-Object -First 1) - if ($Show -ne "None") { - Write-Host -ForegroundColor green -Object "ScriptAnalyzer check for $HeadFunctionPath" + + if ($ScriptAnalyzer) { + if ($Show -ne "None") { + Write-Host -ForegroundColor green -Object "ScriptAnalyzer check for $HeadFunctionPath" + } + Invoke-ScriptAnalyzer -Path $HeadFunctionPath -ExcludeRule $ScriptAnalyzerRulesExclude } - Invoke-ScriptAnalyzer -Path $HeadFunctionPath -ExcludeRule $ScriptAnalyzerRulesExclude } } } \ No newline at end of file diff --git a/tests/Invoke-DbaQuery.Tests.ps1 b/tests/Invoke-DbaQuery.Tests.ps1 index 3aa9c6e774..9e1037d020 100644 --- a/tests/Invoke-DbaQuery.Tests.ps1 +++ b/tests/Invoke-DbaQuery.Tests.ps1 @@ -2,7 +2,6 @@ BeforeAll { $CommandName = (Get-Item $PSCommandPath).Name.Replace(".Tests.ps1", "") - Write-Host -Object "Running $PSCommandPath" -ForegroundColor Cyan $global:TestConfig = Get-TestConfig } @@ -11,12 +10,33 @@ Describe "$CommandName Unit Tests" -Tag 'UnitTests' { Context "Validate parameters" { BeforeAll { $command = Get-Command Invoke-DbaQuery + $expectedParameters = $TestConfig.CommonParameters + $expectedParameters += @( + 'SqlInstance', + 'SqlCredential', + 'Database', + 'Query', + 'QueryTimeout', + 'File', + 'SqlObject', + 'As', + 'SqlParameter', + 'AppendServerInstance', + 'MessagesToOutput', + 'InputObject', + 'ReadOnly', + 'EnableException', + 'CommandType', + 'NoExec' + ) } It "Should only contain our specific parameters" { - [object[]]$params = $command.Parameters.Values.Name | Where-Object { $_ -notin ('whatif', 'confirm') } - [object[]]$knownParameters = 'SqlInstance', 'SqlCredential', 'Database', 'Query', 'QueryTimeout', 'File', 'SqlObject', 'As', 'SqlParameter', 'AppendServerInstance', 'MessagesToOutput', 'InputObject', 'ReadOnly', 'EnableException', 'CommandType', 'NoExec' - $knownParameters += [System.Management.Automation.PSCmdlet]::CommonParameters - (@(Compare-Object -ReferenceObject ($knownParameters | Where-Object { $_ }) -DifferenceObject $params).Count ) | Should -Be 0 + $actualParameters = $command.Parameters.Keys | Where-Object { $PSItem -notin "WhatIf", "Confirm" } + Compare-Object -ReferenceObject $expectedParameters -DifferenceObject $actualParameters | Should -BeNullOrEmpty + } + + It "Has parameter: <_>" -ForEach $expectedParameters { + $command | Should -HaveParameter $PSItem } } Context "Validate alias" { @@ -248,7 +268,7 @@ SELECT @@servername as dbname END" $outparam = New-DbaSqlParameter -Direction Output -Size -1 $sqlparams = @{ - 'newid' = $outparam + 'newid' = $outparam 'somevalue' = 'asd' } $result = Invoke-DbaQuery -SqlInstance $TestConfig.instance2 -Database tempdb -Query "EXEC usp_Insertsomething @somevalue, @newid output" -SqlParameters $sqlparams @@ -269,7 +289,7 @@ SELECT @@servername as dbname $inparam = New-DbaSqlParameter -ParameterName 'somevalue' -SqlDbType VarChar -Value 'example' $outparam = New-DbaSqlParameter -Direction Output -Size -1 $sqlparams = @{ - 'newid' = $outparam + 'newid' = $outparam 'somevalue' = $inparam } $result1 = Invoke-DbaQuery -SqlInstance $TestConfig.instance2 -Database tempdb -Query "EXEC usp_Insertsomething @somevalue, @newid output" -SqlParameters $sqlparams @@ -303,14 +323,14 @@ END" $inparam = @() $inparam += [pscustomobject]@{ somestring = 'string1' - somedate = '2021-07-15T01:02:00' + somedate = '2021-07-15T01:02:00' } $inparam += [pscustomobject]@{ somestring = 'string2' - somedate = '2021-07-15T02:03:00' + somedate = '2021-07-15T02:03:00' } $sqlparams = @{ - 'newid' = $outparam + 'newid' = $outparam 'sometable' = New-DbaSqlParameter -SqlDbType structured -Value (ConvertTo-DbaDataTable -InputObject $inparam) -TypeName 'dbatools_tabletype' } $result = Invoke-DbaQuery -SqlInstance $TestConfig.instance2 -Database tempdb -Query "EXEC usp_Insertsomething @sometable, @newid output" -SqlParameters $sqlparams @@ -353,4 +373,4 @@ SELECT 2 $results = Invoke-DbaQuery -SqlInstance $TestConfig.instance2 -Query "select cast(null as hierarchyid)" $results.Column1 | Should -Be "NULL" } -} +} \ No newline at end of file diff --git a/tests/appveyor.pester.ps1 b/tests/appveyor.pester.ps1 index 6fdfe48bd2..bf77c937d9 100644 --- a/tests/appveyor.pester.ps1 +++ b/tests/appveyor.pester.ps1 @@ -162,8 +162,7 @@ function Get-CodecovReport($Results, $ModuleBase) { function Get-PesterTestVersion($testFilePath) { $testFileContent = Get-Content -Path $testFilePath -Raw - if ($testFileContent -match '#Requires\s+-Module\s+@\{\s+ModuleName="Pester";\s+ModuleVersion="5\.') - { + if ($testFileContent -match '#Requires\s+-Module\s+@\{\s+ModuleName="Pester";\s+ModuleVersion="5\.') { return '5' } return '4' @@ -225,7 +224,6 @@ if (-not $Finalize) { Add-AppveyorTest -Name $appvTestName -Framework NUnit -FileName $f.FullName -Outcome Running $PesterRun = Invoke-Pester @PesterSplat $PesterRun | Export-Clixml -Path "$ModuleBase\PesterResults$PSVersion$Counter.xml" - $outcome = "Passed" if ($PesterRun.FailedCount -gt 0) { $trialno += 1 Update-AppveyorTest -Name $appvTestName -Framework NUnit -FileName $f.FullName -Outcome "Failed" -Duration $PesterRun.Time.TotalMilliseconds @@ -239,7 +237,7 @@ if (-not $Finalize) { #start the round for pester 5 tests # Remove any previously loaded pester module Remove-Module -Name pester -ErrorAction SilentlyContinue - # Import pester 4 + # Import pester 5 Import-Module pester -RequiredVersion 5.6.1 Write-Host -Object "appveyor.pester: Running with Pester Version $((Get-Command Invoke-Pester -ErrorAction SilentlyContinue).Version)" -ForegroundColor DarkGreen $Counter = 0 @@ -255,6 +253,7 @@ if (-not $Finalize) { $pester5Config = New-PesterConfiguration $pester5Config.Run.Path = $f.FullName $pester5config.Run.PassThru = $true + $pester5config.Output.Verbosity = "None" #opt-in if ($IncludeCoverage) { $CoverFiles = Get-CoverageIndications -Path $f -ModuleBase $ModuleBase @@ -271,11 +270,11 @@ if (-not $Finalize) { } else { $appvTestName = "$($f.Name), attempt #$trialNo" } - Write-Host -Object "Running $($f.FullName)" -ForegroundColor Cyan + Write-Host -Object "Running $($f.FullName) ..." -ForegroundColor Cyan -NoNewLine Add-AppveyorTest -Name $appvTestName -Framework NUnit -FileName $f.FullName -Outcome Running $PesterRun = Invoke-Pester -Configuration $pester5config + Write-Host -Object "`rCompleted $($f.FullName) in $([int]$PesterRun.Duration.TotalMilliseconds)ms" -ForegroundColor Cyan $PesterRun | Export-Clixml -Path "$ModuleBase\Pester5Results$PSVersion$Counter.xml" - $outcome = "Passed" if ($PesterRun.FailedCount -gt 0) { $trialno += 1 Update-AppveyorTest -Name $appvTestName -Framework NUnit -FileName $f.FullName -Outcome "Failed" -Duration $PesterRun.Duration.TotalMilliseconds @@ -355,7 +354,7 @@ if (-not $Finalize) { $results5 = @(Get-ChildItem -Path "$ModuleBase\Pester5Results*.xml" | Import-Clixml) - $failedcount += $results | Select-Object -ExpandProperty FailedCount | Measure-Object -Sum | Select-Object -ExpandProperty Sum + $failedcount += $results5 | Select-Object -ExpandProperty FailedCount | Measure-Object -Sum | Select-Object -ExpandProperty Sum # pester 5 output $faileditems = $results5 | Select-Object -ExpandProperty Tests | Where-Object { $_.Passed -notlike $True } if ($faileditems) { @@ -363,10 +362,10 @@ if (-not $Finalize) { $faileditems | ForEach-Object { $name = $_.Name [pscustomobject]@{ - Path = $_.Path -Join '/' - Name = "It $name" - Result = $_.Result - Message = $_.ErrorRecord -Join "" + Path = $_.Path -Join '/' + Name = "It $name" + Result = $_.Result + Message = $_.ErrorRecord -Join "" } } | Sort-Object Path, Name, Result, Message | Format-List throw "$failedcount tests failed."