How to mock a call to an exe file with Pester?
I found a way to mock the call to this executable files:
function Create-Object
{
$exp = '& "C:\temp\my.exe"'
Invoke-Expression -Command $exp
}
And the test with the mock should looks like:
Describe "Create-NewObject" {
Context "Create-Object" {
It "Runs" {
Mock Invoke-Expression {return {$true}} -ParameterFilter {($Command -eq '& "C:\temp\my.exe"')
Create-Object| Should Be $true
}
}
}
Yes, unfortunately, as of Pester 4.8.1:
- you cannot mock external executables by their full paths (e.g,
C:\Windows\System32\cmd.exe
) - you can mock them by file name only (e.g.,
cmd
), but beware that in older Pester versions the mock is only called for invocations that explicitly use the.exe
extension (e.g.,cmd.exe
) - see this (obsolete) GitHub issue
Your own workaround is effective, but it involves Invoke-Expression
, which is awkward; Invoke-Expression
should generally be avoided
Here's a workaround that uses a helper function, Invoke-External
, which wraps the invocation of external programs and, as a function, can itself be mocked, using a -ParameterFilter
to filter by executable path:
In your code, define the Invoke-External
function and then use it to make your call to c:\temp\my.exe
:
# Helper function for invoking an external utility (executable).
# The raison d'être for this function is to allow
# calls to external executables via their *full paths* to be mocked in Pester.
function Invoke-External {
param(
[Parameter(Mandatory=$true)]
[string] $LiteralPath,
[Parameter(ValueFromRemainingArguments=$true)]
$PassThruArgs
)
& $LiteralPath $PassThruArgs
}
# Call c:\temp\my.exe via invoke-External
# Note that you may pass arguments to pass the executable as usual (none here):
Invoke-External c:\temp\my.exe
Then, to mock the call to c:\temp\my.exe
in your Pester tests:
Mock Invoke-External -ParameterFilter { $LiteralPath -eq 'c:\temp\my.exe' } `
-MockWith { $true }
Note: If you only have one call to an external executable in your code, you can omit the -ParameterFilter
argument.