Following on from the previous the Mocking Missing Cmdlets with Pester and Mocking Missing Cmdlet ErrorAction with Pester posts, I also encountered (yet) another interesting problem when attempting to mock cmdlets that were not present on the test system. This one is pretty similar to the -ErrorAction edge-case but involves the pipeline. Here’s a pseudo test that was failing:
Describe 'Mocking Missing Cmdlet Pipeline Example' { Function Get-VM { [CmdletBinding()] param ($Name) } Function Remove-VM { [CmdletBinding()] param ($Name) } InModuleScope 'xVMHyper-V' { It 'Calls Remove-VM' { Mock Get-VM -ParameterFilter { $Name -eq 'TestVM' } -MockWith { return 'TestVM' } Mock Remove-VM -ParameterFilter { $Name -eq 'TestVM' } -MockWith { } Get-VM -Name 'TestVM' | Remove-VM; Assert-MockCalled Remove-VM -Scope It; } } }
In the above example, we wish to mock both the Get-VM and Remove-VM cmdlets and assert that the Remove-VM cmdlet is called. If we run this on a system that does not have the Hyper-V cmdlets installed we receive the following error:
Executing all tests in 'C:\Users\Iain\Desktop\TestPipeline.Tests.ps1' Describing Mocking Pipeline Example Remove-VM : The input object cannot be bound to any parameters for the command either because the command does not take pipeline input or the input and its properties do not match any of the parameters that take pipeline input. At C:\Users\Iain\Desktop\TestPipeline.Tests.ps1:11 char:37 + Get-VM -Name 'TestVM' | Remove-VM; + ~~~~~~~~~ + CategoryInfo : InvalidArgument: (TestVM:String) [Remove-VM], ParameterBindingException + FullyQualifiedErrorId : InputObjectNotBound,Remove-VM [-] Calls Remove-VM 1.35s Expected Remove-VM to be called at least 1 times but was called 0 times at line: 518 in C:\Users\Iain\OneDrive\Powershell\Modules\Pester\Functions\Mock.ps1 Tests completed in 1.35s Passed: 0 Failed: 1 Skipped: 0 Pending: 0
The error message is fairly self-explanatory. Just like your standard Advanced Function definition, we need to indicate that a parameter needs to be able to accept input via the pipeline using the ValueFromPipeline attribute. To fix this we just need to add the Parameter attribute to our stub function definition:
Describe 'Mocking Pipeline Example' { Function Get-VM { [CmdletBinding()] param ($Name) } Function Remove-VM { [CmdletBinding()] param ( [Parameter(ValueFromPipeline = $true)] $Name) } InModuleScope 'xVMHyper-V' { It 'Calls Remove-VM' { Mock Get-VM -ParameterFilter { $Name -eq 'TestVM' } -MockWith { return 'TestVM' } Mock Remove-VM -ParameterFilter { $Name -eq 'TestVM' } -MockWith { } Get-VM -Name 'TestVM' | Remove-VM; Assert-MockCalled Remove-VM -Scope It; } } }
Whilst it’s not rocket-science – just in case someone else runs into it – I thought it would be worth quickly documenting! Here’s the working example:
Executing all tests in 'C:\Users\Iain\Desktop\TestPipeline.Tests.ps1' Describing Mocking Pipeline Example [+] Calls Remove-VM 74ms Tests completed in 74ms Passed: 1 Failed: 0 Skipped: 0 Pending: 0