Background
In PR #549 (comment), @SrBlackVoid raised that wrapping entire public function test files in InModuleScope JiraPS { ... } is discouraged in Pester v5.
This is well-sourced and correct:
- Pester v5 docs (Testing within Modules): "Avoid putting InModuleScope around your Describe and It blocks. InModuleScope prevents you from properly testing your published functions, does not ensure that your functions are actually published and slows down test discovery by loading the module."
- Jakub Jares (core Pester maintainer) in pester/Pester#2109: "One case where you should avoid InModuleScope is when you are testing a public function [...]
Mock -ModuleName <module> should be used instead."
Current State
- All 60 public test files wrap everything in
InModuleScope JiraPS { ... }
- All 27 private test files also use
InModuleScope (correct — that's what it's for)
- Public tests already use
-ModuleName JiraPS on most Mock and Should -Invoke calls, making the outer InModuleScope largely redundant
Why It Matters
When public function tests run inside InModuleScope:
- They bypass the module export mechanism, so they don't verify functions are actually exported
- They can accidentally access private state, masking integration issues
- Test discovery is slower because the module is loaded during discovery
- Tests don't reflect how consumers actually call the module
Migration Complexity
Three complications make this a standalone project:
Write-MockDebugInfo dependency — Used in ~300+ mock scriptblocks across ~57 files. Currently dot-sourced inside InModuleScope, making it available in the module's session state where mocks execute. After migration, needs to be injected separately.
- ~16
Mock calls without -ModuleName — In 11 files. These work today only because they're inside InModuleScope. Each needs -ModuleName JiraPS added.
- ~160
Should -Invoke -CommandName calls without -ModuleName — In 20 files. Same issue.
Implementation Plan
Migration Pattern
Each public test file currently looks like:
BeforeDiscovery {
. "$PSScriptRoot/../../Helpers/TestTools.ps1"
Initialize-TestEnvironment
$script:moduleToTest = Resolve-ModuleSource
Import-Module $script:moduleToTest -Force -ErrorAction Stop
}
InModuleScope JiraPS {
Describe "SomeFunction" -Tag 'Unit' {
BeforeAll {
. "$PSScriptRoot/../../Helpers/TestTools.ps1"
# mocks, definitions...
}
# tests...
}
}
After migration:
BeforeDiscovery {
. "$PSScriptRoot/../../Helpers/TestTools.ps1"
Initialize-TestEnvironment
$script:moduleToTest = Resolve-ModuleSource
Import-Module $script:moduleToTest -Force -ErrorAction Stop
}
Describe "SomeFunction" -Tag 'Unit' {
BeforeAll {
. "$PSScriptRoot/../../Helpers/TestTools.ps1"
InModuleScope JiraPS { . "$PSScriptRoot/../../Helpers/TestTools.ps1" }
# mocks (all with -ModuleName JiraPS), definitions...
}
# tests...
}
Per-File Checklist
For each of the 60 public test files:
- Remove the
InModuleScope JiraPS { } wrapper around Describe
- Add
InModuleScope JiraPS { . TestTools.ps1 } in BeforeAll to inject Write-MockDebugInfo into the module scope for mock scriptblocks
- Add
-ModuleName JiraPS to any Mock calls missing it (~16 calls in 11 files)
- Add
-ModuleName JiraPS to any Should -Invoke -CommandName calls missing it (~160 calls in 20 files)
- Run the test file individually to verify
Batching Strategy
Split into manageable PRs of ~10-15 files each, grouped by function area:
- Batch 1:
Add-Jira* functions (7 files)
- Batch 2:
Get-Jira* functions part 1 (10 files)
- Batch 3:
Get-Jira* functions part 2 (10 files)
- Batch 4:
Remove-Jira* functions (10 files)
- Batch 5:
Set-Jira* / Move-Jira* / Invoke-Jira* (7 files)
- Batch 6:
New-Jira* / Find-Jira* / Format-Jira / Resolve-JiraError (9 files)
- Batch 7: Remaining files + final cleanup (7 files)
Out of Scope
- Private function tests (
Tests/Functions/Private/) — InModuleScope is appropriate there per Pester guidance, though narrowing to inside It blocks could be a separate effort
- Changes to
Write-MockDebugInfo itself or TestTools.ps1
Verification
After each batch: Invoke-Build -Task Clean, Build, Test must pass with 0 failures across all platforms (Windows PS5, Windows PS7, Ubuntu, macOS).
Background
In PR #549 (comment), @SrBlackVoid raised that wrapping entire public function test files in
InModuleScope JiraPS { ... }is discouraged in Pester v5.This is well-sourced and correct:
Mock -ModuleName <module>should be used instead."Current State
InModuleScope JiraPS { ... }InModuleScope(correct — that's what it's for)-ModuleName JiraPSon mostMockandShould -Invokecalls, making the outerInModuleScopelargely redundantWhy It Matters
When public function tests run inside
InModuleScope:Migration Complexity
Three complications make this a standalone project:
Write-MockDebugInfodependency — Used in ~300+ mock scriptblocks across ~57 files. Currently dot-sourced insideInModuleScope, making it available in the module's session state where mocks execute. After migration, needs to be injected separately.Mockcalls without-ModuleName— In 11 files. These work today only because they're insideInModuleScope. Each needs-ModuleName JiraPSadded.Should -Invoke -CommandNamecalls without-ModuleName— In 20 files. Same issue.Implementation Plan
Migration Pattern
Each public test file currently looks like:
BeforeDiscovery { . "$PSScriptRoot/../../Helpers/TestTools.ps1" Initialize-TestEnvironment $script:moduleToTest = Resolve-ModuleSource Import-Module $script:moduleToTest -Force -ErrorAction Stop } InModuleScope JiraPS { Describe "SomeFunction" -Tag 'Unit' { BeforeAll { . "$PSScriptRoot/../../Helpers/TestTools.ps1" # mocks, definitions... } # tests... } }After migration:
BeforeDiscovery { . "$PSScriptRoot/../../Helpers/TestTools.ps1" Initialize-TestEnvironment $script:moduleToTest = Resolve-ModuleSource Import-Module $script:moduleToTest -Force -ErrorAction Stop } Describe "SomeFunction" -Tag 'Unit' { BeforeAll { . "$PSScriptRoot/../../Helpers/TestTools.ps1" InModuleScope JiraPS { . "$PSScriptRoot/../../Helpers/TestTools.ps1" } # mocks (all with -ModuleName JiraPS), definitions... } # tests... }Per-File Checklist
For each of the 60 public test files:
InModuleScope JiraPS { }wrapper around DescribeInModuleScope JiraPS { . TestTools.ps1 }in BeforeAll to injectWrite-MockDebugInfointo the module scope for mock scriptblocks-ModuleName JiraPSto anyMockcalls missing it (~16 calls in 11 files)-ModuleName JiraPSto anyShould -Invoke -CommandNamecalls missing it (~160 calls in 20 files)Batching Strategy
Split into manageable PRs of ~10-15 files each, grouped by function area:
Add-Jira*functions (7 files)Get-Jira*functions part 1 (10 files)Get-Jira*functions part 2 (10 files)Remove-Jira*functions (10 files)Set-Jira*/Move-Jira*/Invoke-Jira*(7 files)New-Jira*/Find-Jira*/Format-Jira/Resolve-JiraError(9 files)Out of Scope
Tests/Functions/Private/) —InModuleScopeis appropriate there per Pester guidance, though narrowing to insideItblocks could be a separate effortWrite-MockDebugInfoitself orTestTools.ps1Verification
After each batch:
Invoke-Build -Task Clean, Build, Testmust pass with 0 failures across all platforms (Windows PS5, Windows PS7, Ubuntu, macOS).