In PowerShell session states provides modules with a private space for internal variables, functions and more.
Each session state also keeps its own set of scopes.
In addition to module-specific session states you also have a default global session state for everything else.
While this isolation is useful it also adds some complexity, especially for scriptblocks as they’re usually bound to (runs in) the session state they were created in.
This is how a exported module function can invoke internal functions in the module that you can’t use directly or even see with Get-Command.
When using the Mock-command Pester publishes the new mock in the current session state.
You can change this by providing a module name using -ModuleName SomeModuleName.
In the failed test Invoke-Command is used directly from the test code which should execute in the global session state, so we didn’t need to override it this time.
However, Mock itself is not invoked from the test code, but from the New-SequentialResultsMock which is now part the HelperModule.
This also means the function is executed in the module’s session state. As a result Mock published the Invoke-Command-mock inside the module’s session state,
making it invisible in our test code which instead ended up calling the original command.
Usually I would place New-SequentialResultsMock in a ps1-file and dot-source it inside a BeforeAll-block. That would keep everything in the same session state and we’d avoid the problem.
This time I promised a fix, so we’ll adjust (over-engineer?) the helper to also work as part of a module.
Instead of calling Mock directly from our helper, we should do it from the same session state used to call New-SequentialResultsMock, making the helper transparent to Mock.
For this to work we need to:
Capture the session state used by the caller
Create a scriptblock to invoke Mock from that is not bound to any specific session state
Invoke the unbound scriptblock in our desired session state
In this post we’ve improved the mock helper-function, making it more portable and easier to maintain and distribute as part of a module.
While working on this we’ve also had a brief introduction to both session states and what it means to have a bound scriptblock.
You can find links spread around the article if you’re interested in reading more about these topics.