powershellpesterpowershell-7.0pester-5

Use a PowerShell hash's key/values with Pester TestCases


I would like to pass the key/values of a PowerShell hash to a Pester unit test, via the TestCases parameter:

BeforeAll {
  $Expected = @{
    Address1='Address1'
    Address2='Address2'
    City='City'
    RegionCode='RegionCode'
    PostalCode='PostalCode'
  }
}

BeforeEach {
  Mock Invoke-SqlCmd
  Invoke-MyFunction @Expected
}

It "sets the column '<Name>' with the value '<Value>'" -TestCases ( $Optional.GetEnumerator() | ForEach-Object { @{Name=$_.Key; Value=$_.Value} } ) {
    param($Name, $Value)
    
    $Test = "*{0}='{1}'*" -f $Name, $Value

    Assert-MockCalled Invoke-Sqlcmd -ParameterFilter {
        $Query -like $Test
    }

}

But can't seem to get the hash's properties 'shaped' correctly to get the tests to work correctly.


Solution

  • Anything that you need to build the test cases needs to be in a BeforeDiscovery { ... } block. The code in BeforeAll { ... } gets deferred until execution of the tests, however your $expected hashtable needs to be available earlier than that before discovery in order to build each of the tests from your test cases. In addition to that you need to nest your It { ... } blocks in either a Describe or Context block

    Update: per your comment - In order to make $Expected available to the test scopes without duplicating the assignment in the BeforeEach block you can set the variable's scope to script scope

    BeforeDiscovery {
        $script:Expected = @{
            Address1   = 'Value_Address1'
            Address2   = 'Value_Address2'
            City       = 'Value_City'
            RegionCode = 'Value_RegionCode'
            PostalCode = 'Value_PostalCode'
        }
    }
    
    Describe "Need a describe or context block" {
        BeforeEach {
            Mock Invoke-SqlCmd
            Invoke-MyFunction @Expected
        }
    
        It "sets the column '<Name>' with the value '<Value>'" -TestCases (
             $Expected.GetEnumerator() | 
                ForEach-Object { @{Name = $_.Key; Value = $_.Value } } 
        ) {
            #   param($Name, $Value)
    
            $Test = "*{0}='{1}'*" -f $Name, $Value
    
            #   Assert-MockCalled Invoke-Sqlcmd -ParameterFilter {
            #       $Query -like $Test
            #   }
    
        }
    }
    

    Output

    Pester v5.3.1
    
    Starting discovery in 1 files.
    Discovery found 5 tests in 25ms.
    Running tests.
    
    Running tests from 'C:\temp\powershell\pester.tests.ps1'
    Describing Need a describe or context block
      [+] sets the column 'RegionCode' with the value 'Value_RegionCode' 8ms (4ms|4ms)
      [+] sets the column 'City' with the value 'Value_City' 2ms (1ms|1ms)
      [+] sets the column 'Address2' with the value 'Value_Address2' 5ms (1ms|3ms)
      [+] sets the column 'PostalCode' with the value 'Value_PostalCode' 3ms (1ms|2ms)
      [+] sets the column 'Address1' with the value 'Value_Address1' 3ms (1ms|2ms)
    Tests completed in 168ms
    Tests Passed: 5, Failed: 0, Skipped: 0 NotRun: 0
    

    See Pester's v5 Discovery and Run docs

    Paraphrased from that page:
    This is what happens during the initial Discovery phase when you run Invoke-Pester