Search code examples
powershelltestingpester

Testing with Pester 5.3.3


I have written a function to write the errors that occur in my functions in a csv file, this function is called in the catch block of my functions. I would like to write a Test in Pester to check that my function works correctly, but to be honest I don't know where to start, I have tried some things but they don't work for me, I have also been reading in the documentation but I am still not clear, I would appreciate any help/comments.

Here is the function for which I want to write a Test in Pester:

function Write-Logs {
    param (
        [ValidateSet("Error")]$MessageType,
        [string][Parameter(Mandatory=$true)]$Message,
        $LogFilePath,
        $Source
    )
    $CSVLogPath = Join-Path -Path $PSScriptRoot -ChildPath ".\errorslog.csv"
    $CSVLogObject = [PSCustomObject] @{
        Date = Get-Date
        Message = $Message
        MessageType = $MessageType
        Source = $Source
    }
    $CSVLogObject | Export-Csv -Path $CSVLogPath -NoTypeInformation -Encoding UTF8 -Append
}

and so I´m calling the function in the catch block:

    catch {
        Write-Logs -LogFilePath:$CSVLogPath -Message:$Error[0].Exception.Message `
        -Source:"FunctionName()" -MessageType:"Error"
        return
    }

Solution

  • Continuing from my comments, here is some code.

    First make the function testable, by actually using the -LogFilePath parameter. This way you can write the log to a temporay file during testing. Due to the default value you can still use it without -LogFilePath when calling it from normal code.

    function Write-Logs {
        param (
            [ValidateSet("Error")]$MessageType,
            [string][Parameter(Mandatory=$true)]$Message,
            $LogFilePath = (Join-Path -Path $PSScriptRoot -ChildPath ".\errorslog.csv"),
            $Source
        )
        $CSVLogObject = [PSCustomObject] @{
            Date = Get-Date
            Message = $Message
            MessageType = $MessageType
            Source = $Source
        }
        $CSVLogObject | Export-Csv -Path $LogFilePath -NoTypeInformation -Encoding UTF8 -Append
    }
    

    Test code:

    BeforeAll {
        . $PSCommandPath.Replace('.Tests.ps1','.ps1')
    }
    
    Describe "Write-Logs" {
        BeforeEach{
            # Mock Get-Date so it returns a constant value suitable for testing
            $expectedDate = [DateTime]::new( 2022, 06, 28, 12, 36, 21 )
            Mock Get-Date { return $expectedDate }
        }   
    
        It "writes the expected CSV" {
        
            # You might read this from a file using Import-Csv
            $expectedCsv = [PSCustomObject]@{
                Date = $expectedDate
                Message = 'test message'
                MessageType = 'Error'
                Source = 'test source'
            }
    
            # Write log to temp file (Pester cleans it automatically, when It block ends)
            $testLogPath = "TestDrive:\test.log"
            Write-Logs -LogFilePath $testLogPath -MessageType $expectedCsv.MessageType -Message $expectedCsv.Message -Source $expectedCsv.Source
    
            $actualCsv = Import-Csv $testLogPath
    
            # Test if $expectedCsv equals $actualCsv
            Compare-Object $expectedCsv $actualCsv -Property Date, Message, MessageType, Source | Should -BeNullOrEmpty
        }
    }
    
    • TestDrive: is a temporary drive created by Pester for each script block. It is very convenient for writing temporary files because Pester cleans it automatically when the script block ends. See Pester docs.
    • Once you got some basic tests working, you might want to improve your test code by using data-driven tests. This avoids duplication as you only need a single test, that can be fed from different data sets. See Pester docs, especially section "Providing external data to tests".