Search code examples
powershelltestingmockingpester

It skips it-statement when executing function in Pester, but shouldn't


I am trying to test a Function in an script file that is testing the connection to a PC. I am trying to do that by calling the mock "Test-Connection" from an other Script in an Pester Test.

When I run Temp.Testing.ps1

describe 'Test Error Handling' {
    $myDir = Split-Path -parent $PSCommandPath  
    $testFile = "$myDir\TryToRenameComputer.ps1"
    .$testFile

    mock 'Test-Connection' { $false }

    $pathForLogs = "C:\temp\Logs.txt"

    it 'exits if Test-Connection Failed'{
        TryToRenameComputer -OldName "OldName"
        Assert-MockCalled 'Test-Connection' -Times 1 -Scope It 
    }
}

TryToRenameComputer.ps1

function TryToRenameComputer {
    param([parameter(Mandatory=$true)]
            [string]$computerName)

    if (!(Test-Connection -ComputerName $computerName -Quiet)) {
        exit
    }
}

it skips the it-statement and shows me no errors. Only "Describing Test Error Handling".

Expected Result: Expected Result

Actual Result: Actual Result

I already tried running a other Function and it worked. Also when I am running multiple it-statements all get skipped when I call the Function in 1 it-statement. I also tried rewriting it so it is no function anymore and it worked.


Solution

  • The problem is likely occurring because of the exit statement in your code. This is getting executed because in the if statement before it you are using -not via its shorthand of ! to test for the result of Test-Connection and because your Mock sets Test-Connection to $false.

    By using exit you are immediately terminating the PowerShell host, which is then stopping your tests from executing/completing.

    Instead of using exit consider using break or return to stop the execution of the function without terminating the script. Or if you potentially do want to terminate the script, consider using throw as you can then stop the parent script when an exception has occurred.

    You could then modify your tests to test for that throw as that is the result you expect to occur when test-connection returns $false. For example:

    function TryToRenameComputer {
        param([parameter(Mandatory=$true)]
                [string]$computerName)
    
        if (!(Test-Connection -ComputerName $computerName -Quiet)) {
            Thow "Could not connect to $computerName"
        }
    }
    
    describe 'Test Error Handling' {
        $myDir = Split-Path -parent $PSCommandPath  
        $testFile = "$myDir\TryToRenameComputer.ps1"
        .$testFile
    
        mock 'Test-Connection' { $false }
    
        $pathForLogs = "C:\temp\Logs.txt"
    
        it 'Throws an error if Test-Connection Failed'{
            { TryToRenameComputer -OldName "OldName" } | Should -Throw
            Assert-MockCalled 'Test-Connection' -Times 1 -Scope It 
        }
    }
    

    There's no easy way to handle exit in your tests and its generally a bit of an anti-pattern when you're writing code for automation.