|
| 1 | +# Pester v4 to v5 Migration Guide |
| 2 | + |
| 3 | +## CORE PESTER v5 REQUIREMENTS |
| 4 | + |
| 5 | +### Mandatory Header Structure |
| 6 | +Every test file must include this header: |
| 7 | + |
| 8 | +```powershell |
| 9 | +#Requires -Module @{ ModuleName="Pester"; ModuleVersion="5.0" } |
| 10 | +param( |
| 11 | + $ModuleName = "YourModuleName", |
| 12 | + $CommandName = "StaticCommandName", # Always use static command name |
| 13 | + $PSDefaultParameterValues = $TestConfig.Defaults |
| 14 | +) |
| 15 | +``` |
| 16 | + |
| 17 | +**Critical Requirements:** |
| 18 | +- Replace "StaticCommandName" with the actual command name being tested as a static string |
| 19 | +- **Remove all dynamic command name derivation** from file paths or directory structures |
| 20 | +- Strip out all `knownParameters` validation code (old Pester v4 pattern) |
| 21 | + |
| 22 | +### Critical Structural Changes |
| 23 | + |
| 24 | +#### Test Block Organization |
| 25 | +- **All setup code** must be in `BeforeAll` or `BeforeEach` blocks |
| 26 | +- **All cleanup code** must be in `AfterAll` or `AfterEach` blocks |
| 27 | +- **All test assertions** must be in `It` blocks |
| 28 | +- **No loose code** allowed in `Describe` or `Context` blocks |
| 29 | +- **Never use `-ForEach` parameter** on any test blocks |
| 30 | + |
| 31 | +```powershell |
| 32 | +# Pester v5 Structure |
| 33 | +Describe $CommandName { |
| 34 | + BeforeAll { |
| 35 | + # All setup code here |
| 36 | + } |
| 37 | +
|
| 38 | + AfterAll { |
| 39 | + # All cleanup code here |
| 40 | + } |
| 41 | +
|
| 42 | + Context "Specific scenario" { |
| 43 | + BeforeAll { |
| 44 | + # Context-specific setup |
| 45 | + } |
| 46 | +
|
| 47 | + It "Should do something" { |
| 48 | + # Test assertions only |
| 49 | + } |
| 50 | + } |
| 51 | +} |
| 52 | +``` |
| 53 | + |
| 54 | +### Variable Scoping Changes |
| 55 | +- Replace all `$script:` with `$global:` for variables that need to persist across Pester blocks |
| 56 | +- Pester v5 has stricter scoping - variables in `BeforeAll` may not be available in `It` blocks without proper scoping |
| 57 | +- Add explicit scope declarations when variables cross Pester block boundaries |
| 58 | + |
| 59 | +### PowerShell Syntax Updates Required for Pester v5 |
| 60 | + |
| 61 | +#### Variable References |
| 62 | +- Replace `$_` with `$PSItem` (recommended for clarity, except where `$_` is required for compatibility) |
| 63 | + |
| 64 | +#### Skip Conditions |
| 65 | +- Use boolean values for skip conditions (`$true`/`$false`), not strings |
| 66 | + |
| 67 | +#### Array Operations |
| 68 | +- Replace `$results.Count` with `$results.Status.Count` for accurate counting |
| 69 | +- Add explicit array initialization: `$array = @()` |
| 70 | +- Wrap result collection in array subexpression operator: `$results = @(Get-Something)` |
| 71 | + |
| 72 | +#### Parameter Quoting |
| 73 | +Remove unnecessary quotes from parameter values: |
| 74 | +```powershell |
| 75 | +# Convert this: |
| 76 | +"$CommandName" -Tag "IntegrationTests" |
| 77 | +# To this: |
| 78 | +$CommandName -Tag IntegrationTests |
| 79 | +``` |
| 80 | + |
| 81 | +#### String Formatting |
| 82 | +- Replace multi-line concatenated strings with here-strings when appropriate |
| 83 | + |
| 84 | +### Resource Management |
| 85 | +- Always include cleanup code in `AfterAll`/`AfterEach` blocks |
| 86 | +- Use `-ErrorAction SilentlyContinue` on cleanup operations |
| 87 | +- Create unique temporary resources using `Get-Random` |
| 88 | + |
| 89 | +```powershell |
| 90 | +BeforeAll { |
| 91 | + $tempPath = "$env:TEMP\TestRun-$(Get-Random)" |
| 92 | + $resourcesToCleanup = @() |
| 93 | +} |
| 94 | +
|
| 95 | +AfterAll { |
| 96 | + Remove-Item -Path $tempPath -Recurse -ErrorAction SilentlyContinue |
| 97 | + Remove-Item -Path $resourcesToCleanup -ErrorAction SilentlyContinue |
| 98 | +} |
| 99 | +``` |
| 100 | + |
| 101 | +### Where-Object Conversion Rules |
| 102 | +Transform Where-Object script blocks to direct property comparisons when possible: |
| 103 | + |
| 104 | +```powershell |
| 105 | +# Pester v5 Preferred - direct property comparison |
| 106 | +$master = $databases | Where-Object Name -eq "master" |
| 107 | +$systemDbs = $databases | Where-Object Name -in "master", "model", "msdb", "tempdb" |
| 108 | +
|
| 109 | +# Required - script block for complex filtering only |
| 110 | +$hasParameters = (Get-Command $CommandName).Parameters.Values.Name | Where-Object { $PSItem -notin ("WhatIf", "Confirm") } |
| 111 | +``` |
| 112 | + |
| 113 | +Only use script blocks when direct property comparison is not possible. |
| 114 | + |
| 115 | +## MIGRATION CHECKLIST |
| 116 | + |
| 117 | +**Header and Structure:** |
| 118 | +- [ ] Added mandatory `#Requires` header |
| 119 | +- [ ] Replaced dynamic command name derivation with static command name |
| 120 | +- [ ] Stripped out old `knownParameters` validation code |
| 121 | +- [ ] Moved all loose code into appropriate `BeforeAll`/`AfterAll` blocks |
| 122 | +- [ ] Removed any `-ForEach` parameters from test blocks |
| 123 | +- [ ] All test assertions properly placed in `It` blocks |
| 124 | + |
| 125 | +**Variable Scoping:** |
| 126 | +- [ ] Changed `$script:` to `$global:` where needed |
| 127 | +- [ ] Added explicit scope declarations for cross-block variables |
| 128 | +- [ ] Verified variable scoping works across Pester blocks |
| 129 | + |
| 130 | +**Syntax Transformations:** |
| 131 | +- [ ] Replaced `$_` with `$PSItem` (except where compatibility requires `$_`) |
| 132 | +- [ ] Replaced string-based skip conditions with boolean values |
| 133 | +- [ ] Updated array operations (`$results.Count` → `$results.Status.Count`) |
| 134 | +- [ ] Added explicit array initialization where needed |
| 135 | +- [ ] Removed unnecessary parameter quotes |
| 136 | +- [ ] Applied Where-Object conversions where possible |
| 137 | +- [ ] Replaced concatenated strings with here-strings where appropriate |
| 138 | + |
| 139 | +**Resource Management:** |
| 140 | +- [ ] Added proper cleanup code with error suppression |
| 141 | +- [ ] Created unique temporary resources using `Get-Random` |
| 142 | +- [ ] Ensured all created resources have corresponding cleanup |
| 143 | + |
| 144 | +**Migration Policy:** |
| 145 | +- [ ] Do not invent new integration tests - if they don't exist, there's a reason |
0 commit comments