代码之家  ›  专栏  ›  技术社区  ›  fourpastmidnight

Pester-Gherkin测试:“找不到名为'PSBoundParameters'的变量”

  •  1
  • fourpastmidnight  · 技术社区  · 6 年前

    Get-ParameterValues ,签字人 @Jaykul ,以及 elovelan . 我选择使用elovelan的不声明参数的版本。我可以确认,就我在命令行进行的测试而言,该函数按预期工作。

    我将这个函数合并到一个私有模块中,我将它作为一个通用函数来编写(当然要有适当的属性,谢谢 @杰库尔 !!),因此,我正试图为它编写单元测试。但是,当运行测试时,我得到了错误 Cannot find a variable with the name 'PSBoundParameters'.

    纠缠测试因错误而失败 找不到名为“PSBoundParameters”的变量。

    here

    文件功能

    Feature: Get-ParameterValues
    
      As a PowerShell function author
      In order to more easily deal with function parameters
      I want to be able to automatically populate a dictionary
      containing the supplied function arguments or the parameter's
      default value if the argument was not supplied
      So that I can reduce boilerplate code when dealing with
      function parameters.
    
      Background: A test function with parameters
    
        Given a test function
          """
          function global:Test {
              [CmdletBinding()]
              param(
                  [Parameter(Position = 0)]
                  $ValueWithNoDefault,
                  [Parameter(Position = 1)]
                  $ValueWithDefault = 'default',
                  [Parameter(Position = 2)]
                  $ValueWithNullDefault = $null
              )
    
              $Parameters = (Get-ParameterValues)
              $Parameters
          }
          """
    
      Scenario Outline: Get-ParameterValues returns a dictionary with the expected key and value
    
        Given the value '<Value>' is provided for the '<Parameter>' parameter
         When 'global:Test' is invoked
         Then the hashtable '<ContainsAKey>' a key for the parameter
          And the resolved parameter value is '<ExpectedValue>'.
    
        Examples: Examples using parameter ValueWithNoDefault
          | Parameter            | Value         | Contains         | ExpectedValue    |
          | ValueWithNoDefault   | <No value>    | does not contain | <Does Not Exist> |
          | ValueWithNoDefault   | `$null        | contains         | `$null           |
          | ValueWithNoDefault   | { `$foo = 1 } | contains         | { `$foo = 1 }    |
          | ValueWithNoDefault   | `$false       | contains         | `$false          |
          | ValueWithNoDefault   | `$true        | contains         | `$true           |
          | ValueWithNoDefault   | ""            | contains         | ""               |
          | ValueWithNoDefault   | 0             | contains         | 0                |
          | ValueWithNoDefault   | @()           | contains         | @()              |
          | ValueWithNoDefault   | 1             | contains         | 1                |
    

    步骤定义

    BeforeEachFeature {
        Import-Module -Name "${pwd}\path-to\My-Module.psd1" -Scope Global -Force
    
        filter global:ConvertFrom-TableCellValue {
            Param(
                [Parameter(Mandatory=$True, Position=0, ValueFromPipeline=$True)]
                [AllowNull()]
                [AllowEmptyString()]
                $Value
            )
    
            Process {
                if ($Value -eq '$null') {
                    $Value = $null
                }
    
                switch -Regex ($Value) {
                    '^"?\{\s*(?<ScriptBody>.*)\s*\}"?$'   { $Value = [ScriptBlock]::Create($Matches.ScriptBody) }
                    '(?<StringValue>".*")'                { $Value = ($Matches.StringValue -as [string]) }
                    '$?(?i:(?<Boolean>true|false))'       { $Value = [Boolean]::Parse($Matches.Boolean) }
                    '^\d+$'                               { $Value = $Value -as [int] }
                    default                               {  }
                }
    
                $Value
            }
        }
    }
    
    AfterEachFeature {
        $Module = Get-Module -Name "My-Module"
        if ($Module) {
            $Module.Name | Remove-Module
        }
    
        if (Test-Path "Function:\global:ConvertTo-Parameter") {
            Remove-Item Function:\global:ConvertTo-Parameter
        }
    }
    
    Given "a test function" {
        param ([string]$func)
    
        Invoke-Expression $func
    
        $f = Get-Item 'Function:\Test'
        $f | Should -Not -BeNull
    }
    
    Given "the value '(?<Value>.*)' is provided for the '(?<Parameter>\S*)' parameter" {
        param(
            [object]$Value,
            [string]$Parameter
        )
    
        $Value = ConvertFrom-TableCellValue $Value
        if ($Value -ne "<No value>") {
            $Context = @{ $Parameter = $Value }
        } else {
            $Context = @{}
        }
    }
    
    When "'(?<CmdletName>.*)' is invoked" {
        [CmdletBinding()]
        Param ([string]$CmdletName)
    
        # NOTE: I probably don't need the if block, but I added this during debugging of this issue...just-in-case.
        # NOTE: The test fails in this step definition at this point when it executes the `Test` function which calls Get-ParameterValues.
        if ($Context.Keys.Count -gt 0) {
            $actual = &$CmdletName @Context
        } else {
            $actual = &$CmdletName
        }
    
        Write-Debug $actual.GetType().FullName
    }
    
    Then "the hashtable '(?<ContainsAKey>(does not contain|contains))' a key for the parameter" {
        param([string]$ContainsAKey)
    
        ($Context.ContainsKey($Parameter) -and $actual.ContainsKey($Context.$Parameter)) | Should -Be ($ContainsAKey -eq 'contains')
    }
    

    psake version 4.7.4
    Copyright (c) 2010-2017 James Kovacs & Contributors
    
    Executing InstallDependencies
    Executing Init
    Executing Test
    Testing all features in 'C:\src\git\My-Module\Specs\features' with tags: 'Get-ParameterValues'
    
    Feature: Get-ParameterValues
           As a PowerShell function author
           In order to more easily deal with function parameters
           I want to be able to automatically populate a dictionary
           containing the supplied function arguments or the parameter's
           default value if the argument was not supplied
           So that I can reduce boilerplate code when dealing with
           function parameters.
    
      Scenario: Get-ParameterValues returns a dictionary with the expected key and value
      Examples:Examples using parameter ValueWithNoDefault
        [+] Given a test function 59ms
        [+] Given the value '<No value>' is provided for the 'ValueWithNoDefault' parameter 187ms
        [-] When 'global:Test' is invoked 48ms
          at <ScriptBlock>, C:\src\git\My-Module\Public\Utility\Get-ParameterValues.ps1: line 74
          74:     $BoundParameters = Get-Variable -Scope 1 -Name PSBoundParameters -ValueOnly
    
          From C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 35
          Cannot find a variable with the name 'PSBoundParameters'.
        [-] Then the hashtable 'does not contain' a key for the parameter 201ms
          at <ScriptBlock>, C:\src\git\My-Module\Specs\features\steps\Utility\Get-ParameterValues.steps.ps1: line 38
          38:     ($Context.ContainsKey($Parameter) -and $actual.ContainsKey($Context.$Parameter)) | Should -Be ($ContainsAKey -eq 'contains')
    
          From C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 36
          You cannot call a method on a null-valued expression.
        [?] And the resolved parameter value is '<Does Not Exist>'. 40ms
          Could not find implementation for step!
          At And, C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 37
    

    谁能告诉我为什么 $PSBoundParameters 字典不存在于 函数,即使参数传递给 Test 功能?(我觉得这可能与PowerShell范围界定规则有关,因为 When 脚本块有“脚本”范围——我试图通过确保 函数在中声明 global

    更新

    所以,沿着这条路走下去可能是PowerShell作用域的问题,我只是不明白,我修改了我的小黄瓜 Given 步骤如下:

    Given a test function
          """
          function global:Test {
              [CmdletBinding()]
              param(
                  [Parameter(Position = 0)]
                  $ValueWithNoDefault,
                  [Parameter(Position = 1)]
                  $ValueWithDefault = 'default',
                  [Parameter(Position = 2)]
                  $ValueWithNullDefault = $null
              )
    
              $DebugPreference = 'Continue'
              if ($PSBoundParameters) {
                  Write-Debug "`$PSBoundParameters = $(ConvertTo-JSON $PSBoundParameters)"
              } else {
                  Write-Debug "Unable to find `$PSBoundParameters automatic variable."
              }
              $Parameters = (Get-ParameterValues)
              $Parameters
          }
          """
    

    下面是对前两个表项运行测试的输出(请参阅上面的原始功能文件):

    psake version 4.7.4
    Copyright (c) 2010-2017 James Kovacs & Contributors
    
    Executing InstallDependencies
    Executing Init
    Executing Test
    Testing all features in 'C:\src\git\My-Module\Specs\features' with tags: 'Get-ParameterValues'
    
    Feature: Get-ParameterValues
           As a PowerShell function author
           In order to more easily deal with function parameters
           I want to be able to automatically populate a dictionary
           containing the supplied function arguments or the parameter's
           default value if the argument was not supplied
           So that I can reduce boilerplate code when dealing with
           function parameters.
    
      Scenario: Get-ParameterValues returns a dictionary with the expected key and value
      Examples:Examples using parameter ValueWithNoDefault
        [+] Given a test function 54ms
    DEBUG: $Parameter: ValueWithNoDefault
    DEBUG: $Value: <No value>
        [+] Given the value '<No value>' is provided for the 'ValueWithNoDefault' 
    parameter 29ms
    DEBUG: Cmdlet: Test
    DEBUG: Context: {
    
    }
    DEBUG: $PSBoundParameters = {
    
    }
        [-] When 'Test' is invoked 47ms
          at <ScriptBlock>, C:\src\git\My-Module\Public\Utility\Get-ParameterValues.ps1: line 74
          74:     $BoundParameters = Get-Variable -Scope 1 -Name PSBoundParameters -ValueOnly
    
          From C:\src\git\My-Module\Specs\features\Utility\Get- ParameterValues.feature: line 41
          Cannot find a variable with the name 'PSBoundParameters'.
    DEBUG: Context: {
    
    }
    DEBUG: actual:
        [+] Then the hashtable 'does not contain' a key for the parameter 61ms
        [?] And the resolved parameter value is '<Does Not Exist>'. 30ms
          Could not find implementation for step!
          At And, C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 43
    DEBUG: $Parameter: ValueWithNoDefault
    DEBUG: $Value:
        [+] Given the value '$null' is provided for the 'ValueWithNoDefault' parameter 14ms
    DEBUG: Cmdlet: Test
    DEBUG: Context: {
        "ValueWithNoDefault":  ""
    }
    DEBUG: $PSBoundParameters = {
        "ValueWithNoDefault":  ""
    }
        [-] When 'Test' is invoked 9ms
          at <ScriptBlock>, C:\src\git\My-Module\Public\Utility\Get-ParameterValues.ps1: line 74
          74:     $BoundParameters = Get-Variable -Scope 1 -Name PSBoundParameters -ValueOnly
    
          From C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 41
          Cannot find a variable with the name 'PSBoundParameters'.
    DEBUG: Context: {
        "ValueWithNoDefault":  ""
    }
    DEBUG: actual:
        [-] Then the hashtable 'contains' a key for the parameter 20ms
          at <ScriptBlock>, C:\src\git\My- Module\Specs\features\steps\Utility\Get-ParameterValues.steps.ps1: line 39
          39:     ($Context.ContainsKey('Parameter') -and 
    $actual.ContainsKey($Context.$Parameter)) | Should -Be ($ContainsAKey -eq 'contains')
          From C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 42
          Expected $true, but got $false.
        [?] And the resolved parameter value is '`$null'. 5ms
          Could not find implementation for step!
          At And, C:\src\git\My-Module\Specs\features\Utility\Get-ParameterValues.feature: line 43
    

    $PSBoundParameters 试验 在中创建的函数 鉴于 只有当它是非null/empty/是“truthy”时才执行步骤(否则我会写一个字符串来说明它不存在)。在任何情况下,即使是在 $null 分配给参数, 定义并存在于 试验 获取参数值 在该函数内部尝试检索 $PSBoundParameters 试验 已确定变量存在于该范围内的函数)。但是,我从Pester测试步骤定义中得到了错误消息。不幸的是,这些结果让我更加困惑。

    0 回复  |  直到 6 年前