在 Azure cmdlet 调用上纠缠模拟错误 PSInvalidCastException

Pester mock error PSInvalidCastException on Azure cmdlet call

我需要 "Pester-test" 2 个 Azure cmdlet,Get-AzureNetworkSecurityGroupSet-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 验证。)