如何使用 Pester 模拟模块不可用的 cmdlet?
How can I use Pester to mock a cmdlet in which the module is not available?
我正在尝试为我的 Azure 自动化运行手册编写 Pester 测试。 Runbook 脚本使用 Get-AutomationVariable
cmdlet,我试图通过以下方式模拟它:
mock 'Get-AutomationVariable' {return "localhost:44300"} -ParameterFilter { $name -eq "host"}
导致错误
CommandNotFoundException: The term 'Get-AutomationVariable' is not
recognized as the name of a cmdlet, function, script file, or operable
program.
Check the spelling of the name, or if a path was included,
verify that the path is correct and try again.
-ModuleName
参数的使用似乎不合适,因为我是从脚本而不是模块调用方法。尝试提供存根模块会导致抛出相同的错误。
. "$here$sut" "CN=teset, OU=Test" "CN=SubCA02, OU=Test"
Get-Module -Name RunbookMock | Remove-Module
New-Module -Name RunbookMock -ScriptBlock {
function Get-AutomationVariable {
[CmdLetBinding()]
param(
[string]$Name
)
""
}
Export-ModuleMember Get-AutomationVariable
} | Import-Module -Force
describe 'Pin-Certificate' {
it 'should add an entry to the pinned certificate list'{
mock 'Get-AutomationVariable' { return "sastoken"} -ParameterFilter { $Name -eq "StorageSasToken"} -
mock 'Get-AutomationVariable' {return "localhost:44300"} -ParameterFilter { $name -eq "host"}
}
}
核心问题是语句的顺序。被测脚本是在模拟声明之前获取的。重新排序声明模拟然后获取脚本的语句解决了这个问题,@MarkWragg 的优秀建议有助于进一步简化代码。其最终工作状态如下
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
function Get-AutomationVariable {
[CmdLetBinding()]
param([string]$Name)
}
describe 'Pin-Certificate' {
it 'should add an entry to the pinned certificate list' {
mock 'Get-AutomationVariable' -MockWith { "sastoken" } -ParameterFilter { $Name -eq "StorageSasToken"}
mock 'Get-AutomationVariable' -MockWith { "localhost:44300" } -ParameterFilter { $Name -eq "host"}
mock 'Invoke-WebRequest' -MockWith { @{ "StatusCode" = "204"; } }
# dot source the sut, invoking the default function
$result = (. "$here$sut" "Subject" "Issuer" "Thumbprint")
$result.Issuer | Should be "Issuer"
$result.Subject | Should Be "Subject"
$result.Thumbprint | Should Be "Thumbprint"
}
根据评论,您的代码应该可以工作。过去我只是声明了一个空函数而不是一个完整的模块。例如:
function MyScript {
Get-FakeFunction
}
Describe 'Some Tests' {
function Get-Fakefunction {}
Mock 'Get-Fakefunction' { write-output 'someresult' }
$Result = MyScript
it 'should invoke Get-FakeFunction'{
Assert-MockCalled 'Get-Fakefunction' -Times 1
}
it 'should return someresult'{
$Result | Should -Be 'someresult'
}
}
我正在尝试为我的 Azure 自动化运行手册编写 Pester 测试。 Runbook 脚本使用 Get-AutomationVariable
cmdlet,我试图通过以下方式模拟它:
mock 'Get-AutomationVariable' {return "localhost:44300"} -ParameterFilter { $name -eq "host"}
导致错误
CommandNotFoundException: The term 'Get-AutomationVariable' is not recognized as the name of a cmdlet, function, script file, or operable program.
Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
-ModuleName
参数的使用似乎不合适,因为我是从脚本而不是模块调用方法。尝试提供存根模块会导致抛出相同的错误。
. "$here$sut" "CN=teset, OU=Test" "CN=SubCA02, OU=Test"
Get-Module -Name RunbookMock | Remove-Module
New-Module -Name RunbookMock -ScriptBlock {
function Get-AutomationVariable {
[CmdLetBinding()]
param(
[string]$Name
)
""
}
Export-ModuleMember Get-AutomationVariable
} | Import-Module -Force
describe 'Pin-Certificate' {
it 'should add an entry to the pinned certificate list'{
mock 'Get-AutomationVariable' { return "sastoken"} -ParameterFilter { $Name -eq "StorageSasToken"} -
mock 'Get-AutomationVariable' {return "localhost:44300"} -ParameterFilter { $name -eq "host"}
}
}
核心问题是语句的顺序。被测脚本是在模拟声明之前获取的。重新排序声明模拟然后获取脚本的语句解决了这个问题,@MarkWragg 的优秀建议有助于进一步简化代码。其最终工作状态如下
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
function Get-AutomationVariable {
[CmdLetBinding()]
param([string]$Name)
}
describe 'Pin-Certificate' {
it 'should add an entry to the pinned certificate list' {
mock 'Get-AutomationVariable' -MockWith { "sastoken" } -ParameterFilter { $Name -eq "StorageSasToken"}
mock 'Get-AutomationVariable' -MockWith { "localhost:44300" } -ParameterFilter { $Name -eq "host"}
mock 'Invoke-WebRequest' -MockWith { @{ "StatusCode" = "204"; } }
# dot source the sut, invoking the default function
$result = (. "$here$sut" "Subject" "Issuer" "Thumbprint")
$result.Issuer | Should be "Issuer"
$result.Subject | Should Be "Subject"
$result.Thumbprint | Should Be "Thumbprint"
}
根据评论,您的代码应该可以工作。过去我只是声明了一个空函数而不是一个完整的模块。例如:
function MyScript {
Get-FakeFunction
}
Describe 'Some Tests' {
function Get-Fakefunction {}
Mock 'Get-Fakefunction' { write-output 'someresult' }
$Result = MyScript
it 'should invoke Get-FakeFunction'{
Assert-MockCalled 'Get-Fakefunction' -Times 1
}
it 'should return someresult'{
$Result | Should -Be 'someresult'
}
}