考虑下面的 Powershell 代码,有没有办法在没有 internalMenuWrapper
函数的情况下模拟 $host.ui.PromptForChoice
?
<#
.Synopsis
wrap the menu so we can mock calls to it
#>
function internalMenuWrapper {
param (
[Parameter(Mandatory=$true)]
$prompt,
[Parameter(Mandatory=$true)]
$options
)
return = $host.ui.PromptForChoice("Waiting for user input", $prompt, [System.Management.Automation.Host.ChoiceDescription[]]$options, 0)
}
<#
.Synopsis
Create a menu with an array of choices and return the result
#>
function Invoke-Menu($prompt, $opts) {
$options = @()
foreach ($opt in $opts) {
$options += $(new-object System.Management.Automation.Host.ChoiceDescription $opt)
}
$index = internalMenuWrapper $prompt $options
$opts[$index]
}
Describe 'Invoke-Menu' {
Context "when called" {
It "returns the object that was selected" {
#mock fails
Mock internalMenuWrapper { return 0 }
$result = Invoke-Menu "test menu" @("pass", "fail")
$result | Should -Be "pass"
}
}
}
最佳答案
如Mike Shepard在评论中指出,Pester 不支持模拟方法,只能模拟命令(cmdlet、函数、别名、外部程序).
您可以使用 Get-Host
cmdlet(而不是 $host
)解决该问题并模拟that:
function Invoke-Menu($prompt, $choices) {
$choiceObjects = [System.Management.Automation.Host.ChoiceDescription[]] $choices
# Use Get-Host instead of $host here; $host cannot be mocked, but Get-Host can.
$index = (Get-Host).ui.PromptForChoice("Waiting for user input", $prompt, $choiceObjects, 0)
$choices[$index]
}
Describe 'Invoke-Menu' {
Context "when called" {
It "returns the object that was selected" {
# Mock Get-Host with a dummy .ui.PromptForChoice() method that instantly
# returns 0 (the first choice).
Mock Get-Host {
[pscustomobject] @{
ui = Add-Member -PassThru -Name PromptForChoice -InputObject ([pscustomobject] @{}) -Type ScriptMethod -Value { return 0 }
}
}
Invoke-Menu 'test menu' '&pass', '&fail' | Should -Be '&pass'
}
}
}
正如您指出的on GitHub ,如果建议的 Read-Choice
cmdlet 曾经实现过(作为 $host.ui.PromptForChoice()
的 PS 友好包装器),则可以直接模拟它(并且没有要测试的自定义代码)。
关于powershell - 如何使用 Pester 模拟 $host.ui.PromptForChoice,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57698737/