簡體   English   中英

Mock 函數應該如何接受 Pester 中的管道輸入?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM