如何使用 Pester 模拟对 exe 文件的调用?
How to mock a call to an exe file with Pester?
在PowerShell中开发脚本,需要调用外部可执行文件(.exe)。目前我正在使用 TDD 方法开发此脚本,因此我需要模拟调用此 .exe 文件。
我试试这个:
Describe "Create-NewObject" {
Context "Create-Object" {
It "Runs" {
Mock '& "c:\temp\my.exe"' {return {$true}}
Create-Object| Should Be $true
}
}
}
我收到了这样的回复:
Describing Create-NewObject
Context Create-Object
[-] Runs 574ms
CommandNotFoundException: Could not find Command & "C:\temp\my.exe"
at Validate-Command, C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1: line 801
at Mock, C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1: line 168
at <ScriptBlock>, C:\T\Create-NewObject.tests.ps1: line 13
Tests completed in 574ms
Passed: 0 Failed: 1 Skipped: 0 Pending: 0 Inconclusive: 0
有没有办法在不将它们封装在函数中的情况下模拟这种调用?
我找到了一种模拟调用此可执行文件的方法:
function Create-Object
{
$exp = '& "C:\temp\my.exe"'
Invoke-Expression -Command $exp
}
模拟测试应该如下所示:
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
}
}
}
是的,不幸的是,从 Pester 4.8.1 开始:
- 你不能通过完整路径模拟外部可执行文件(例如,
C:\Windows\System32\cmd.exe
)
- 你 可以 仅通过 文件名 来模拟它们(例如
cmd
),但要注意在较旧的 Pester 版本中模拟仅在显式使用 .exe
扩展名(例如 cmd.exe
)的调用中调用 - 请参阅 this (obsolete) GitHub issue
is effective, but it involves Invoke-Expression
, which is awkward; Invoke-Expression
should generally be avoided
这是一个使用辅助函数 Invoke-External
的变通方法,它 包装 外部程序的调用,并且作为 函数 , 本身可以被模拟,使用 -ParameterFilter
按可执行路径过滤:
在您的代码中,定义 Invoke-External
函数,然后使用它调用 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
然后,在您的 Pester 测试中模拟对 c:\temp\my.exe
的调用:
Mock Invoke-External -ParameterFilter { $LiteralPath -eq 'c:\temp\my.exe' } `
-MockWith { $true }
注意:如果您的代码中只有 一个 调用外部可执行文件,则可以省略
-ParameterFilter
参数。
我尝试了这个并且似乎有效。
$PathToExe = 'C:\Windows\System32\wevtutil.exe'
New-Item -Path function: -Name $PathToExe -Value { ... }
Mock $PathToExe { ... }
在PowerShell中开发脚本,需要调用外部可执行文件(.exe)。目前我正在使用 TDD 方法开发此脚本,因此我需要模拟调用此 .exe 文件。
我试试这个:
Describe "Create-NewObject" {
Context "Create-Object" {
It "Runs" {
Mock '& "c:\temp\my.exe"' {return {$true}}
Create-Object| Should Be $true
}
}
}
我收到了这样的回复:
Describing Create-NewObject
Context Create-Object
[-] Runs 574ms
CommandNotFoundException: Could not find Command & "C:\temp\my.exe"
at Validate-Command, C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1: line 801
at Mock, C:\Program Files\WindowsPowerShell\Modules\Pester\Functions\Mock.ps1: line 168
at <ScriptBlock>, C:\T\Create-NewObject.tests.ps1: line 13
Tests completed in 574ms
Passed: 0 Failed: 1 Skipped: 0 Pending: 0 Inconclusive: 0
有没有办法在不将它们封装在函数中的情况下模拟这种调用?
我找到了一种模拟调用此可执行文件的方法:
function Create-Object
{
$exp = '& "C:\temp\my.exe"'
Invoke-Expression -Command $exp
}
模拟测试应该如下所示:
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
}
}
}
是的,不幸的是,从 Pester 4.8.1 开始:
- 你不能通过完整路径模拟外部可执行文件(例如,
C:\Windows\System32\cmd.exe
) - 你 可以 仅通过 文件名 来模拟它们(例如
cmd
),但要注意在较旧的 Pester 版本中模拟仅在显式使用.exe
扩展名(例如cmd.exe
)的调用中调用 - 请参阅 this (obsolete) GitHub issue
Invoke-Expression
, which is awkward; Invoke-Expression
should generally be avoided
这是一个使用辅助函数 Invoke-External
的变通方法,它 包装 外部程序的调用,并且作为 函数 , 本身可以被模拟,使用 -ParameterFilter
按可执行路径过滤:
在您的代码中,定义 Invoke-External
函数,然后使用它调用 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
然后,在您的 Pester 测试中模拟对 c:\temp\my.exe
的调用:
Mock Invoke-External -ParameterFilter { $LiteralPath -eq 'c:\temp\my.exe' } `
-MockWith { $true }
注意:如果您的代码中只有 一个 调用外部可执行文件,则可以省略 -ParameterFilter
参数。
我尝试了这个并且似乎有效。
$PathToExe = 'C:\Windows\System32\wevtutil.exe'
New-Item -Path function: -Name $PathToExe -Value { ... }
Mock $PathToExe { ... }