Mocking functions in Pester is easy, you just use Mock
and you are done. But how do you mock a method on an object?
For our model example let’s say we decided to stop a process using wmi
, and copy some files if we were able to successfully stop the process. This scenario would happen for example when you need to update some .dll
s and the program has them loaded. In our case we will just use notepad.exe
, so no locking will actually occur.
Yes, using
wmi
is probably the most complicated way to stop a process, but a bit of complexity is what I am after. 🙂
In to try this out you can try running this snippet in Windows PowerShell. It will start a notepad process, and then immediately kill it:
# try running this to see how it actually behaves |
Inspecting the members on the objects you can see that the $wmiObject
has .Terminate()
method. When called this method returns a result object which has ReturnValue
property, and that property is 0 when the termination succeeded. We will mock all of that.
$wmiObject | Get-Member -Name Terminate |
Here is the how the whole test would look like, followed by explanation of each component:
Describe "Start notepad and kill it" { |
Explanation
Explaining this rather involved example is best done backwards. So let’s start from the Mock
of Get-WmiObject
. As we’ve seen the the first snippet, when the real Get-WmiObject
is called, it returns a process object. In our mock we also return an object:
$mockWmiObject = [PSCustomObject] @{ } |
This fake wmiObject
needs to have .Terminate()
method on it, so we add that:
$mockTerminateMethod = { |
The .Terminate()
method must return a result object with ReturnValue
:
$mockResult = [PSCustomObject] @{ |
Counting the calls
Additionally to this we want to be able to check if the .Terminate()
method was called. We could use script scoped variables for that, but that would make our tests potentially depend on each other. A much better way is to attach the info directly on the mockObject
, and keep reference to it:
# arrange |
All of this combined gives us the big example above, which allows us to mock the functionality as well as count the amount of times the method was invoked.
Summary
Mocking methods in PowerShell is quite easy once you get the flow of it. It relies on shadowing methods by our own script methods. Next time we will look at how to capture the parameters that were passed in.
🌵 A question was asked why am I using
BeforeEach
to setup the mock insteadBeforeAll
. And that is because we share a live reference to an object. Having a single reference to the mock from multiple tests, would make the tests depend on each other, and would make it pretty much the same as if we used script scoped variables in the first place. This way it is slightly slower, but more correct.