You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pester 5嵌套循环中如何访问多个变量?

Pester V4 迁移到 V5:嵌套 -ForEach 循环的变量访问解决方案

问题背景

将Pester测试从V4版本迁移到V5版本时,按照最佳实践将传统foreach()循环替换为Describe -ForEach{}语法,用于检查模块中每个函数的注释式帮助是否完整。V4中数组变量可以在所有Describe/Context/It块中直接访问,但V5要求初始化代码必须放在BeforeDiscovery块中,且子块无法自动继承父块BeforeDiscovery中的变量。当前卡在最后一个-ForEach循环:无法同时访问来自BeforeDiscovery块的$parameterNames和父循环的$helpParameterNames。

V4 原始代码

$commands = Get-Command -Module ModuleName

foreach ($command in $commands) {
    $commandName = $command.Name
    $help = Get-Help $commandName -ErrorAction SilentlyContinue
    
    Describe "Test help for $commandName" -Tag Help {
        
      <It Tests Removed>
        
        Context "Test parameter help for $commandName" {            
            $common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable'
            $parameters = $command.ParameterSets.Parameters | Sort-Object -Property Name -Unique | Where-Object Name -notin $common
            $parameterNames = $parameters.Name
            $helpParameterNames = $help.Parameters.Parameter.Name | Sort-Object -Unique
            
            foreach ($parameter in $parameters) {
                $parameterName = $parameter.Name
                $parameterHelp = $help.parameters.parameter | Where-Object Name -EQ $parameterName               
                
                <It Tests Removed>
            }
            
            foreach ($helpParm in $helpParameterNames) {
                It "Should find parameter $helpParm in the function" {
                    $helpParm -in $parameterNames | Should Be $true
                }
            }
        }
    }
}

V5 迁移中的问题代码

BeforeDiscovery {
    $commands = Get-Command -Module ModuleName
}

Describe "Help Rules" -Tags Build, Help -ForEach $commands {
    BeforeDiscovery {
        $commandName = $_.Name

        $common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable'
        $parameters = (Get-Command $commandName).ParameterSets.Parameters | Where-Object -Property Name -NotIn $common | Sort-Object -Property Name -Unique
        $parameterNames = $parameters.Name
        $help = Get-Help $commandName -Full -ErrorAction SilentlyContinue
    }

    Context "General Rules for $commandName" -ForEach @{help = $help} {

        <It Tests Removed>

        Describe "Parameter Rules for <parameter.Name>" -Tags Help, Parameter -ForEach $parameters {
            
            BeforeAll {
                $parameter = $_.parameters  # 此处错误,应直接取 $_
                $helpParameterNames = $help.Parameters.Parameter.Name | Sort-Object -Unique
                $parameterHelp = $help.parameters.parameter | Where-Object Name -EQ $parameter.Name
            }

            <It Tests Removed>
        }

        It "Should find parameter <helpParameter> in the function" -Tag Help, Parameter -ForEach $helpParameterNames {
            
            BeforeAll {
                $helpParameter = $_
            }

            $helpParameter -in $parameterNames | Should -BeTrue  # 此处无法访问 $parameterNames
        }
    }
}

解决方法

V5的Discovery阶段(BeforeDiscovery、Describe/Context/It的定义)和Run阶段(测试执行)是完全分离的,BeforeDiscovery中的变量不会自动传递到Run阶段。解决核心是:在Discovery阶段将需要的变量打包成自定义对象数组,通过-ForEach传递给子块,确保迭代时能同时拿到所有必要数据。

修改后的完整V5代码

BeforeDiscovery {
    $commands = Get-Command -Module ModuleName
}

Describe "Help Rules" -Tags Build, Help -ForEach $commands {
    BeforeDiscovery {
        $commandName = $_.Name

        $common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable'
        $parameters = (Get-Command $commandName).ParameterSets.Parameters | Where-Object -Property Name -NotIn $common | Sort-Object -Property Name -Unique
        $parameterNames = $parameters.Name
        $help = Get-Help $commandName -Full -ErrorAction SilentlyContinue
        # 打包参数验证所需的两个变量为对象数组
        $helpParamValidationSet = $help.Parameters.Parameter.Name | Sort-Object -Unique | ForEach-Object {
            [PSCustomObject]@{
                HelpParameter = $_
                ExpectedParameterNames = $parameterNames
            }
        }
    }

    Context "General Rules for $commandName" -ForEach @{help = $help; parameters = $parameters} {

        <It Tests Removed>

        Describe "Parameter Rules for <parameter.Name>" -Tags Help, Parameter -ForEach $parameters {
            
            BeforeAll {
                $parameter = $_  # 修正:直接取当前迭代的parameter对象
                $parameterHelp = $help.parameters.parameter | Where-Object Name -EQ $parameter.Name
            }

            <It Tests Removed>
        }

        # 使用打包后的对象数组进行循环,同时拿到两个变量
        It "Should find parameter <HelpParameter> in the function" -Tag Help, Parameter -ForEach $helpParamValidationSet {
            $_.HelpParameter -in $_.ExpectedParameterNames | Should -BeTrue
        }
    }
}

关键修改点说明

  1. 变量打包传递:在Describe的BeforeDiscovery中,将$helpParameterNames和$parameterNames组合成[PSCustomObject]数组$helpParamValidationSet,确保It循环时能同时访问两个变量。
  2. 修正迭代变量取值:在Describe "Parameter Rules for <parameter.Name>"的BeforeAll中,将$parameter = $_.parameters改为$parameter = $_,因为-ForEach $parameters的每个迭代项就是单个参数对象。
  3. 移除冗余BeforeAll:It块中无需额外定义BeforeAll,直接通过$_访问迭代对象的属性即可。

内容的提问来源于stack exchange,提问作者Ninja

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 10:10:49