powershell - Mock 函数应该如何接受 Pester 中的管道输入?

标签 powershell 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 中自动创建的。

你的 Stop-Process Mock 不工作的原因是你用 -ParameterFilter 属性定义了它,这导致它只在定义的参数时被调用是真的。您的过滤器不起作用,因为您将对象类型引用为字符串 ("System.Diagnostics.Process") 而不是类型(用方括号声明)。

Mock 的正确代码是:

Mock stop-process { "Process object passed ! Stopping notepad!" } -ParameterFilter { $InputObject -is [System.Diagnostics.Process[]] }

asked this question of the Pester development team directly他们提出了一个更简单的解决方案,即 -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 is a Pester function (introduced in Pester 3.4.4) that allows you to create "fake" objects of almost any type to run in Pester mocks. These "fake objects" allow your mocks to return the same type as the function it was mocking to pass the result to entities that are strongly typed.

在您的场景中没有必要,但我认为您可能会发现它相关/有趣。

关于powershell - Mock 函数应该如何接受 Pester 中的管道输入?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41892907/

相关文章:

.net - 深度复制PSObject

azure - 如何在Powershell Runbook中将JSON文件内容转换为Powershell对象?

multithreading - 如何使用 PowerShell 多线程以及 Pester Mocks 进行单元测试

windows - Pester 5 变量作用域问题 - BeforeDiscovery/It

powershell - 纠缠自定义错误文本

powershell - 如何在 Pester 中使用 'get arguments for calls made on' 模拟(或以其他方式生成包含实际值和预期值的有用消息)?

powershell - 使用 Powershell 更改大型 CSV 文件中的分隔符

Powershell - SET-ADUSER 修改samaccountname

json - ConvertFrom-Json 将小写 e 转换为大写字母(有时)

powershell - 使用 `pester` 测试 `pester` 版本