[英]How should a Mock function accept pipeline input in Pester?
我对 Pester 很陌生,我正在尝试在 PowerShell 中为一个非常小而简单的函数构建测试:
function Toggle-Notepad {
if (-not ( Get-Process notepad -ErrorAction SilentlyContinue ) )
{
Start-Process -FilePath Notepad
}
else
{
get-process notepad | stop-process
}
}
如果记事本未运行,则此功能仅启动记事本,否则,如果它正在运行,则将其停止。
我设计的测试是这样的:
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"
Describe "Toggle-Notepad" {
Mock Stop-Process { "Process object passed! Stopping notepad!" }
Mock Start-Process { "Notepad is not running,starting it!" } -ParameterFilter { $Filepath -eq "Notepad" }
It "Starts notepad if it is not running" {
Toggle-Notepad | Should be "Notepad is not running,starting it!"
}
It "Stops notepad if it is running" {
Toggle-Notepad | Should be "Process object passed ! Stopping notepad!"
}
}
上述测试按预期运行。
如何重写Stop-Process
函数,以便可以指定此版本用于接受管道输入?
我试过这个,但它不起作用:
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"
Describe "Toggle-Notepad" {
Mock stop-process { "Process object passed ! Stopping notepad" } -ParameterFilter { $InputObject -is "System.Diagnostics.Process" }
Mock Start-Process {"Notepad is not running,starting it!"} -ParameterFilter { $Filepath -eq "Notepad" }
It "Starts notepad if it is not running" {
Toggle-Notepad | Should be "Notepad is not running,starting it!"
}
It "Stops notepad if it is running" {
Toggle-Notepad | Should be "Process object passed ! Stopping notepad!"
}
}
由于Stop-Process
函数正在接受管道输入,我的目标是模拟类似的函数,而不是创建一个不接受任何参数的通用Stop-Process
函数。
有没有 Pester 专家可以提供帮助?
您通常不需要在Mock
手动定义参数,因为被Mock
的函数的参数是在 Mock 中自动创建的。
您的Stop-Process
Mock 不工作的原因是因为您已经使用-ParameterFilter
属性定义了它,这导致它仅在定义的 Parameter 为真时才被调用。 您的过滤器不起作用,因为您将对象类型引用为字符串( "System.Diagnostics.Process"
)而不是类型(用方括号声明)。
Mock 的正确代码是:
Mock stop-process { "Process object passed ! Stopping notepad!" } -ParameterFilter { $InputObject -is [System.Diagnostics.Process[]] }
我直接向 Pester 开发团队询问了这个问题,他们提出了一个更简单的解决方案,即-ParameterFilter { $InputObject }
因为如果它没有填充该类型的有效对象,它将为 null。
这是一个完整的例子:
Describe 'Mocking stop-process' {
Mock Stop-Process {
Write-Host "Mock stopping: $InputObject"
} -ParameterFilter { $InputObject }
It 'Should mock stopping the notepad process' {
Get-Process notepad | Stop-Process | Should Be $null
}
}
另外仅供参考,从 Pester 3.4.4 开始,现在有一个New-MockObject命令,允许您创建任何类型的假对象:
New-MockObject 是一个 Pester 函数(在 Pester 3.4.4 中引入),它允许您创建几乎任何类型的“假”对象以在 Pester 模拟中运行。 这些“假对象”允许您的模拟返回与其模拟的函数相同的类型,以将结果传递给强类型的实体。
在您的场景中没有必要,但我认为您可能会发现它相关/有趣。
您可以像任何其他函数一样模拟接受管道值的函数:
Describe "Toggle-Notepad" {
Mock Stop-Process {
[CmdletBinding()]
param(
[Parameter(ValueFromPipeline = $true)]
$InputObject
)
return "Process object passed! Stopping notepad"
} -ParameterFilter { $InputObject -is "System.Diagnostics.Process" }
Mock Start-Process {
return "Notepad is not running, starting it!"
} -ParameterFilter { $Filepath -eq "Notepad" }
It "Starts notepad if it is not running" {
Toggle-Notepad | Should be "Notepad is not running, starting it!"
}
It "Stops notepad if it is running" {
Toggle-Notepad | Should be "Process object passed! Stopping notepad!"
}
}
另请注意,您Stop-Process
存在拼写错误,因此无法正常工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.