Search code examples
powershellpester

How do I make Pester catch a thrown error?


When I run the following pester test I expect it to catch the expected error but it doesn't. But when I run the test with a different function with a different throw statement it works.

Pester Test:

Describe "Remove-GenericCredential Function Tests" {

  $InternetOrNetworkAddress = 'https://[email protected]'

  Context "Test: Credential does not exist" {

    It "Should have credentials" { 
      { (Remove-GenericCredential -InternetOrNetworkAddress $InternetOrNetworkAddress -Confirm:$false) } | 
        Should Throw "Remove-GenericCredential : Credential $InternetOrNetworkAddress not found" 
    }
  }
}

Error that isn't caught:

 Remove-GenericCredential : Credential https://[email protected] not found
     
 At C:\Users\klocke7\Documents\WindowsPowerShell\Modules\Ford_CredentialManager\Tests\Remove-GenericCredential.Tests.ps1:30  
 char:76  
     + ... xist." { { (Remove-GenericCredential -InternetOrNetworkAddress $Inter ...  
     +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
         + CategoryInfo          : NotSpecified: (:) [Write-Error], WriteErrorException  
         + FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException,Remove-GenericCredential  
     
    [-] This Command threw an error.  The credential does not exist. 44ms  
             Expected: the expression to throw an exception with message {Remove-GenericCredential : Credential
 https://[email protected] not found}, an exception was
 not raised, message was {}  
                 from C:  \Users\klocke7\Documents\WindowsPowerShell\Modules\Ford_CredentialManager\Tests\New-GitHubCredential.Tests.ps1:59  
 char:176  
                 + ... e $UserName -Token 'NotAGitHubTokenSpecialCharacters!@#$%^&*') } | sh ...  
                 +                        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  
             at <ScriptBlock>, C:\Users\klocke7\Documents\WindowsPowerShell\Modules\Ford_CredentialManager\Tests\Remove-GenericCredential.Tests.ps1:  
 line 30  
             30:     It "This Command threw an error.  The credential does not exist." { { (Remove-GenericCredential
 -InternetOrNetworkAddress $InternetOrNetworkAddress -Confirm:$false) } | should throw 'Remove-GenericCredential : Credential
 https://[email protected] not found' }

Solution

  • Per the other answer, the function is throwing a non-terminating error and as such its not being considered to match the test of Should Throw, which is checking for terminating errors.

    There are two ways you could address this:

    1. You could change it so that it throws a terminating error by changing your Write-Error to Throw.
    2. You could change the test to force the function to throw a terminating error even when non-terminating ones occur by using -ErrorAction Stop when you invoke it (I can see you're using -Confirm, I assume you have used [cmdletbinding()] in the function to add the common parameters like -ErrorAction).

    Here's an example of the second solution (I've simulated the function at the top so that I could test this, but you don't need to include that in your test script):

    Function Remove-GenericCredential {
        [cmdletbinding(supportsshouldprocess)]
        Param(
            $InternetOrNetworkAddress
        )
    
        Write-Error "Remove-GenericCredential : Credential $InternetOrNetworkAddress not found"
    }
    
    Describe "Remove-GenericCredential Function Tests" {
        $InternetOrNetworkAddress = 'https://[email protected]'
    
        Context "Test:  Remove-GenericCredential -InternetOrNetworkAddress '$InternetOrNetworkAddress' (Credential does not exist)" {
        It "This Command threw an error.  The credential does not exist." { 
            { (Remove-GenericCredential -InternetOrNetworkAddress $InternetOrNetworkAddress -Confirm:$false -ErrorAction Stop) } | should throw "Remove-GenericCredential : Credential $InternetOrNetworkAddress not found" }
        }
    }
    

    From help Write-Error:

    The Write-Error cmdlet declares a non-terminating error. By default, errors are sent in the error stream to the host program to be displayed, along with output.

    To write a non-terminating error, enter an error message string, an ErrorRecord object, or an Exception object. Use the other parameters of Write-Error to populate the error record.

    Non-terminating errors write an error to the error stream, but they do not stop command processing. If a non-terminating error is declared on one item in a collection of input items, the command continues to process the other items in the collection.

    To declare a terminating error, use the Throw keyword. For more information, see about_Throw (http://go.microsoft.com/fwlink/?LinkID=145153).