Mocking Missing Cmdlets with Pester

A VPN is an essential component of IT security, whether you’re just starting a business or are already up and running. Most business interactions and transactions happen online and VPN

When writing Pester unit tests for your Powershell code you will probably have a need to mock calls to external functions before too long. This process works as you would expect when Pester can locate a defined function/cmdlet with a matching name. However, if Pester cannot find a definition, it will fail.

This problem will normally surface in a Continuous Integration (CI) environment. For me, it was writing the first suite of tests for the xHyper-V DSC resource module. The Hyper-V cmdlets where present on my authoring machine but were not present on the Appveyor build VM.

Here is an overly simplified Pester test that I’ll use for demonstration purposes:

Describe 'Missing Cmdlet Mocking Example' {
    InModuleScope 'xVMHyper-V' {

        It 'Calls Get-VM' {
            Mock Get-VM -MockWith { }
            Get-VM -Name 'TestVM';
            Assert-MockCalled Get-VM -Scope It;
        }

    }
}

If we run the test and Pester cannot locate a defined function then it will report an error. Note: if you run this on a machine with the Hyper-V module installed (and you have a VM called ‘TestVM’) then it will pass – but you knew that already ;).

Describing Missing Cmdlet Mocking Example
 [-] calls Get-VM 474ms
   Could not find Command Get-VM
   at line: 600 in C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1
Tests completed in 474ms

This is easily overcome by defining an empty function within the test file. Note: this will need to be defined within the ‘InModuleScope’ script block if you’re testing a module’s internals.

Describe 'Missing Cmdlet Mocking Example' {
    InModuleScope 'xVMHyper-V' {

        Function Get-VM { }

        It 'Calls Get-VM' {
            Mock Get-VM -MockWith { }
            Get-VM -Name 'TestVM';
            Assert-MockCalled Get-VM -Scope It;
        }

    }
}

The test now passes as we would expect. Yay \o/

Describing Missing Cmdlet Mocking Example
 [+] Calls Get-VM 141ms
Tests completed in 141ms
Passed: 1 Failed: 0 Skipped: 0 Pending: 0

Now, what you really need to know is that for Pester to enumerate and mock parameter filters, those parameters need to be defined on the stub function. If we were to update the test to check for the passing of a particular –Name parameter like so:

Describe 'Missing Cmdlet Mocking Example' {
    InModuleScope 'xVMHyper-V' {

        Function Get-VM { }

        It 'Calls Get-VM' {
            Mock Get-VM –ParameterFilter { $Name –eq ‘TestVM } -MockWith { }
            Get-VM -Name 'TestVM';
            Assert-MockCalled Get-VM –ParameterFilter { $Name –eq ‘TestVM’ } -Scope It;
        }

    }
}

When we run the test it will now fail again.

Describing Missing Cmdlet Mocking Example
 [-] Calls Get-VM 131ms
   Expected Get-VM to be called at least 1 times but was called 0 times
   at line: 518 in C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1
Tests completed in 131ms
Passed: 0 Failed: 1 Skipped: 0 Pending: 0

For Pester to enumerate the dynamic parameters on the function, it needs to have the parameters (only the one’s you’re interested in) defined. This can easily be fixed like so:

Describe 'Missing Cmdlet Mocking Example' {
    InModuleScope 'xVMHyper-V' {

        Function Get-VM { param ($Name) }

        It 'Calls Get-VM' {
            Mock Get-VM –ParameterFilter { $Name –eq ‘TestVM } -MockWith { }
            Get-VM -Name 'TestVM';
            Assert-MockCalled Get-VM –ParameterFilter { $Name –eq ‘TestVM’ } -Scope It;
        }

    }
}

The tests will now once again pass successfully!

Describing Missing Cmdlet Mocking Example
 [+] Calls Get-VM 169ms
Tests completed in 169ms
Passed: 1 Failed: 0 Skipped: 0 Pending: 0

Hopefully this helps someone and saves some time. It took me a while to work out what was going on as I had the cmdlets available on my development machine but the tests were failing when running in an Appveyor VM. Perhaps I should submit a pull request to get this put into the Pester help documentation?!

siteadmin

siteadmin

Leave a Replay

Recent Posts

Sign up for our Newsletter

Click edit button to change this text. Lorem ipsum dolor sit amet, consectetur adipiscing elit