Today you write -ModuleName MyModule on every Mock, or you wrap the test in InModuleScope. Both are things you have to know about before you can write a working test, and the people who get this wrong are exactly the people who have not read that page yet.
We already infer, but only in the case we want people to stop using. From Mock.ps1:
if (-not $PSBoundParameters.ContainsKey('ModuleName') -and $null -ne $SessionState.Module) {
$ModuleName = $SessionState.Module.Name
}
That fires when the caller is already in module scope, which today means you used InModuleScope.
The rule
Watch what BeforeAll imported.
- snapshot
Get-Module objects before the container's BeforeAll
- after it runs, take the modules that are not in the snapshot
- drop any that appear in another new module's
RequiredModules
- exactly one left, that is the module under test, use it as the default
-ModuleName
- zero, or more than one, bind nothing and behave exactly as today
No configuration and no new syntax, it reads the Import-Module that people already write. Every failure falls back to current behaviour, so it cannot break an existing suite.
Compare by object identity, not by name
This is the detail that decides the implementation.
|
by name and path |
by object identity |
| fresh import |
detected |
detected |
-Force reimport of an already loaded module |
missed |
detected |
| two modules imported |
|
2, refuse to guess |
-Force creates a new PSModuleInfo, so identity comparison catches the reimport that a name comparison misses. That matters because reimport is the normal case once the second test file runs in the same session. A name based check would bind nothing exactly where people need it.
Dependencies
Without step 3 any module that has RequiredModules looks ambiguous. RequiredModules is populated on the loaded PSModuleInfo, so it filters cleanly:
newly loaded: 2 -> Helper, Main
required by others: Helper
candidates after filter: 1 -> Main
What I did not check
Deeper chains, A requires B requires C. The filter should hold but I did not test it.
Where the snapshot belongs in our lifecycle, container setup or the BeforeAll boundary.
This does nothing for discovery. BeforeAll runs after discovery, so -ForEach (Get-Command -Module X) still needs the module imported earlier than this.
Part of #2996.
🤖
Today you write
-ModuleName MyModuleon everyMock, or you wrap the test inInModuleScope. Both are things you have to know about before you can write a working test, and the people who get this wrong are exactly the people who have not read that page yet.We already infer, but only in the case we want people to stop using. From
Mock.ps1:That fires when the caller is already in module scope, which today means you used
InModuleScope.The rule
Watch what
BeforeAllimported.Get-Moduleobjects before the container'sBeforeAllRequiredModules-ModuleNameNo configuration and no new syntax, it reads the
Import-Modulethat people already write. Every failure falls back to current behaviour, so it cannot break an existing suite.Compare by object identity, not by name
This is the detail that decides the implementation.
-Forcereimport of an already loaded module-Forcecreates a newPSModuleInfo, so identity comparison catches the reimport that a name comparison misses. That matters because reimport is the normal case once the second test file runs in the same session. A name based check would bind nothing exactly where people need it.Dependencies
Without step 3 any module that has
RequiredModuleslooks ambiguous.RequiredModulesis populated on the loadedPSModuleInfo, so it filters cleanly:What I did not check
Deeper chains, A requires B requires C. The filter should hold but I did not test it.
Where the snapshot belongs in our lifecycle, container setup or the
BeforeAllboundary.This does nothing for discovery.
BeforeAllruns after discovery, so-ForEach (Get-Command -Module X)still needs the module imported earlier than this.Part of #2996.
🤖