Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I Powershell Pester Test for ThrowTerminatingError

How do I Powershell Pester Test for ThrowTerminatingError ?

catch
{
    $PSCmdlet.ThrowTerminatingError( $PSItem )
}

Output:

Missed command:

File                  Class Function          Line Command
----                  ----- --------          ---- -------
Test-ServerOnline.ps1       Test-ServerOnline   50 $PSCmdlet.ThrowTerminatingError( $PSItem )
like image 210
Eric Dunn Avatar asked Jan 25 '23 14:01

Eric Dunn


1 Answers

In order to catch a terminating error (an exception) in a Pester test:

  • you must enclose the input command in a script block ({ ... })

  • and test for whether such an error did / did not occur with
    Should -Throw / Should -Not -Throw

Note: If you also want to handle non-terminating errors this way, which Should -Throw does not handle:

  • If the input command calls a cmdlet / advanced function, add common parameter -ErrorAction Stop to it, which promotes the (first) non-terminating error to a (script)-terminating (fatal) one.

  • Otherwise, set $ErrorActionPreference = 'Stop' as the first statement inside the script block.


Examples:

Note: For brevity, the following snippets aren't full Pester tests and call just the Pester Should cmdlet; however, you can call them as-is, which case a successful test is implied by receiving no output. See the bottom section for a complete example.

# Note the { ... } around the command.
{ 1 / 0 } | Should -Throw

The above test passes, because 1 / 0 creates a statement-terminating error, which is the same error type that $PSCmdlet.ThrowTerminatingError() produces.

With a non-terminating error promoted to a terminating one with -ErrorAction Stop

# Note: Without -ErrorAction Stop, the test would fail, because
#       not finding a file is a non-terminating error.
{ Get-Item NoSuchFile -ErrorAction Stop } | Should -Throw

Additionally, you can test for specific error IDs, using the -ErrorId parameter:

{ 1 / 0 } | Should -Throw -ErrorId RuntimeException

The above test passes, because the error record produced by the statement-terminating error triggered with 1 / 0 (as also recorded in the automatic $Error variable), has a .FullyQualifiedErrorId value of RuntimeException (verify with $Error[0].FullyQualifiedErrorId afterwards).

Note: -ErrorId performs literal substring matching, so that -ErrorId Runtime would work too in the command above.

Alternatively, you can test for specific exception types, using the -ExceptionType parameter:

{ 1 / 0 } | Should -Throw -ExceptionType System.Management.Automation.RuntimeException

Note that you must pass the full type name; omitting the System. component (which PowerShell often allows) is not recognized by -ExceptionType.

To identify the type of the exception associated with the most recent error, use $Error[0].Exception.GetType().FullName


Complete example:

Store the following in a *.tests.ps1 file and invoke it either directly or via Invoke-Pester.
All of these tests should pass.

Describe "Error-handling tests" {

  BeforeAll {
    # Define an advanced function that generates a terminating error.
    function Get-FooTerminating {
      [CmdletBinding()]
      param()
      # When invoked by Pester, $PSCmdlet.ThrowTerminatingError()
      # would have the same effect here, but note that $PSCmdlet.ThrowTerminatingError()
      # creates a *statement*-terminating error, whereas Throw creates a more
      # severe *script*-terminating (thread-terminating) error.
      Throw "me for a loop"
    }
    
    # Define an advanced function that generates a non-terminating error.
    function Get-FooNonTerminating {
      [CmdletBinding()]
      param()
      Write-Error "Something went mildly wrong."
    }

  }

  It "A terminating error throws." {
    { Get-FooTerminating } | Should -Throw
  }

  It "A non-terminating error doesn't throw." {
    # Note: Non-terminating errors are *passed through*, so
    #       we silence them with 2>$null here.
    { Get-FooNonTerminating 2>$null } | Should -Not -Throw
  }

  It "A non-terminating error promoted to a terminating one does throw." {
    { Get-FooNonTerminating -ErrorAction Stop } | Should -Throw
  }

  It "A fully qualified error ID can be tested for." {
    # Test for a (substring of) the error record's .FullyQualifiedErrorId 
    { NoSuchCommand } | Should -Throw -ErrorId CommandNotFound
  }

  It "A specific exception type can be tested for." {
    # Note the need to specify the type name *in full*, including the
    # 'System.' part
    { NoSuchCommand } | Should -Throw -ExceptionType System.Management.Automation.CommandNotFoundException
  }


}
like image 129
mklement0 Avatar answered Jan 29 '23 20:01

mklement0