在 Azure cmdlet 调用上纠缠模拟错误 PSInvalidCastException
Pester mock error PSInvalidCastException on Azure cmdlet call
我需要 "Pester-test" 2 个 Azure cmdlet,Get-AzureNetworkSecurityGroup 和 Set-AzureNetworkSecurityRule 来自一个 PowerShell 函数模块,如下所示:
$nsg = Get-AzureNetworkSecurityGroup -Name $NsgName
Set-AzureNetworkSecurityRule -Name $NsgRule.name `
-Type Outbound `
# ... other properties here ...
-NetworkSecurityGroup $nsg |
Format-List -Property Name,Location,Label
参数 $NsgName、$NsgRule 不是那么重要,问题是我在模拟 Set-AzureNetworkSecurityRule 时收到错误,例如:
Mock Get-AzureNetworkSecurityGroup { return [PSCustomObject] @{ Name='Any' } }
Mock Set-AzureNetworkSecurityRule
Mock Format-List
错误说:
[-] Error occurred in Describe block 100ms
PSInvalidCastException: Cannot convert the "@{Name=Any}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.INetworkSecurityGroup".
ArgumentTransformationMetadataException: Cannot convert the "@{Name=Any}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.INetworkSecurityGroup".
ParameterBindingArgumentTransformationException: Cannot process argument transformation on parameter 'NetworkSecurityGroup'. Cannot convert the "@{Name=Any}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.INetworkSecurityGroup".
很清楚发生了什么,问题是我不知道如何模拟 INetworkSecurityGroup 类型的对象。如果模拟两个 Azure cmdlet,我最初的期望是没有问题。
我也试过使用 -MockWith:
模拟 Set-AzureNetworkSecurityRule
Mock Set-AzureNetworkSecurityRule -MockWith {@{NetworkSecurityGroup='test-stuff'}}
运气不好。
谁能给我指出正确的方向?
提前致谢
UPDATE 完整 Describe 声明
第一次尝试
$environmentConfig = (Get-AzureEnvironmentConfig "Staging")
Describe 'Set-NetworkSecurityRuleFromObject' {
$role = ($environmentConfig.roles | Where { $_.role_name -eq 'Web'})
$nsgName = Get-NetworkSecurityGroupName -EnvironmentConfig $environmentConfig -Role $role
$rule = $role.nsg_rules.outbound[0]
Mock Get-AzureNetworkSecurityGroup
Mock Set-AzureNetworkSecurityRule
Set-NetworkSecurityRuleFromObject -NsgName -$nsgName -NsgRule $rule -NsgRuleType "Outbound"
It 'Should call mocked functions at least once' {
Assert-MockCalled Get-AzureNetworkSecurityGroup -Times 1 -Scope Describe
Assert-MockCalled Set-AzureNetworkSecurityRule -Times 1 -Scope Describe
}
}
关联PS模块函数调用:
Get-AzureNetworkSecurityGroup -Name $NsgName |
Set-AzureNetworkSecurityRule -Name $NsgRule.name `
-Type $NsgRuleType `
# More parameter initialization here ...
-Protocol $NsgRule.protocol |
Format-List -Property Name,Location,Label
第二次尝试,PS 函数的另一个实现无效:
$nsg = Get-AzureNetworkSecurityGroup -Name $NsgName
$nsg |
Set-AzureNetworkSecurityRule -Name $NsgRule.name `
-Type $NsgRuleType `
# More parameter initialization here ...
-Protocol $NsgRule.protocol |
Format-List -Property Name,Location,Label
第三次尝试
Describe 'Set-NetworkSecurityRuleFromObject' {
[ ... ]
Mock Get-AzureNetworkSecurityGroup { return [PSCustomObject] @{ Name='Any' } }
Mock Set-AzureNetworkSecurityRule
Set-NetworkSecurityRuleFromObject -NsgName -$nsgName -NsgRule $rule -NsgRuleType "Outbound"
It 'Should call mocked functions at least once' {
Assert-MockCalled Get-AzureNetworkSecurityGroup -Times 1 -Scope Describe
Assert-MockCalled Set-AzureNetworkSecurityRule -Times 1 -Scope Describe
}
}
这仍然是使用 Pester 做的最具挑战性的事情之一。您需要以这样的方式模拟 Get-AzureNetworkSecurityGroup
,以便它 returns 是一个有效的对象,稍后将传递给 Set-AzureNetworkSecurityGroup
,并且弄清楚如何做到这一点有时会很棘手。在这种特定情况下,还算不错:
Mock Get-AzureNetworkSecurityGroup {
return New-Object Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.SimpleNetworkSecurityGroup('Any', 'someLocation', 'someLabel')
}
因为这个函数参数是一个接口类型,你也可以用 C#(或 PowerShell v5)快速写一个 class 来实现这个接口;有时这可能更可取,如果实际 class 在您创建实例后立即开始执行 "stuff"。然而,这个 SimpleNetworkSecurityGroup
class 除了保存数据之外并没有真正做任何事情,并且按原样使用是安全的。 (通过 ILSpy 验证。)
我需要 "Pester-test" 2 个 Azure cmdlet,Get-AzureNetworkSecurityGroup 和 Set-AzureNetworkSecurityRule 来自一个 PowerShell 函数模块,如下所示:
$nsg = Get-AzureNetworkSecurityGroup -Name $NsgName
Set-AzureNetworkSecurityRule -Name $NsgRule.name `
-Type Outbound `
# ... other properties here ...
-NetworkSecurityGroup $nsg |
Format-List -Property Name,Location,Label
参数 $NsgName、$NsgRule 不是那么重要,问题是我在模拟 Set-AzureNetworkSecurityRule 时收到错误,例如:
Mock Get-AzureNetworkSecurityGroup { return [PSCustomObject] @{ Name='Any' } }
Mock Set-AzureNetworkSecurityRule
Mock Format-List
错误说:
[-] Error occurred in Describe block 100ms
PSInvalidCastException: Cannot convert the "@{Name=Any}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.INetworkSecurityGroup".
ArgumentTransformationMetadataException: Cannot convert the "@{Name=Any}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.INetworkSecurityGroup".
ParameterBindingArgumentTransformationException: Cannot process argument transformation on parameter 'NetworkSecurityGroup'. Cannot convert the "@{Name=Any}" value of type "System.Management.Automation.PSCustomObject" to type "Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.INetworkSecurityGroup".
很清楚发生了什么,问题是我不知道如何模拟 INetworkSecurityGroup 类型的对象。如果模拟两个 Azure cmdlet,我最初的期望是没有问题。
我也试过使用 -MockWith:
模拟 Set-AzureNetworkSecurityRuleMock Set-AzureNetworkSecurityRule -MockWith {@{NetworkSecurityGroup='test-stuff'}}
运气不好。
谁能给我指出正确的方向?
提前致谢
UPDATE 完整 Describe 声明
第一次尝试
$environmentConfig = (Get-AzureEnvironmentConfig "Staging")
Describe 'Set-NetworkSecurityRuleFromObject' {
$role = ($environmentConfig.roles | Where { $_.role_name -eq 'Web'})
$nsgName = Get-NetworkSecurityGroupName -EnvironmentConfig $environmentConfig -Role $role
$rule = $role.nsg_rules.outbound[0]
Mock Get-AzureNetworkSecurityGroup
Mock Set-AzureNetworkSecurityRule
Set-NetworkSecurityRuleFromObject -NsgName -$nsgName -NsgRule $rule -NsgRuleType "Outbound"
It 'Should call mocked functions at least once' {
Assert-MockCalled Get-AzureNetworkSecurityGroup -Times 1 -Scope Describe
Assert-MockCalled Set-AzureNetworkSecurityRule -Times 1 -Scope Describe
}
}
关联PS模块函数调用:
Get-AzureNetworkSecurityGroup -Name $NsgName |
Set-AzureNetworkSecurityRule -Name $NsgRule.name `
-Type $NsgRuleType `
# More parameter initialization here ...
-Protocol $NsgRule.protocol |
Format-List -Property Name,Location,Label
第二次尝试,PS 函数的另一个实现无效:
$nsg = Get-AzureNetworkSecurityGroup -Name $NsgName
$nsg |
Set-AzureNetworkSecurityRule -Name $NsgRule.name `
-Type $NsgRuleType `
# More parameter initialization here ...
-Protocol $NsgRule.protocol |
Format-List -Property Name,Location,Label
第三次尝试
Describe 'Set-NetworkSecurityRuleFromObject' {
[ ... ]
Mock Get-AzureNetworkSecurityGroup { return [PSCustomObject] @{ Name='Any' } }
Mock Set-AzureNetworkSecurityRule
Set-NetworkSecurityRuleFromObject -NsgName -$nsgName -NsgRule $rule -NsgRuleType "Outbound"
It 'Should call mocked functions at least once' {
Assert-MockCalled Get-AzureNetworkSecurityGroup -Times 1 -Scope Describe
Assert-MockCalled Set-AzureNetworkSecurityRule -Times 1 -Scope Describe
}
}
这仍然是使用 Pester 做的最具挑战性的事情之一。您需要以这样的方式模拟 Get-AzureNetworkSecurityGroup
,以便它 returns 是一个有效的对象,稍后将传递给 Set-AzureNetworkSecurityGroup
,并且弄清楚如何做到这一点有时会很棘手。在这种特定情况下,还算不错:
Mock Get-AzureNetworkSecurityGroup {
return New-Object Microsoft.WindowsAzure.Commands.ServiceManagement.Network.NetworkSecurityGroup.Model.SimpleNetworkSecurityGroup('Any', 'someLocation', 'someLabel')
}
因为这个函数参数是一个接口类型,你也可以用 C#(或 PowerShell v5)快速写一个 class 来实现这个接口;有时这可能更可取,如果实际 class 在您创建实例后立即开始执行 "stuff"。然而,这个 SimpleNetworkSecurityGroup
class 除了保存数据之外并没有真正做任何事情,并且按原样使用是安全的。 (通过 ILSpy 验证。)