Is there a way to test / assert output from Write-Host using Pester?
Asked Answered
G

1

9

I'm writing tests for a fairly complex script and there's one particular function in the script that will output different series of logging messages to the user. I would like to assert whether a particular logging message is being displayed.

The main issue is that I don't know what parameter is implicitly handling the text that I'm passing the Write-Host cmdlet.

Here is some code that captures the premise of what I am trying to do...

Function to test

function TestFunction($TestInput) {
    if ($TestInput -contains 1) {
        Write-Host "TestInput contains a 1"
    }

    if ($TestInput -contains 3 ) {
        Write-Host "TestInput contains a 3"
    }

    if ($TestInput -contains 4 ) {
        Write-Host "TestInput contains a 4"
    }
}

Pester test

Describe "TestFunction" {
    It "should call Write-Host with appropriate message if 1 or 3 is passed" {
        Mock Write-Host {}
        TestFunction -TestInput @(1, 2, 3)
        Assert-MockCalled Write-Host -Exactly 2 -Scope It
        Assert-MockCalled Write-Host -Exactly 1 -Scope It -ParameterFilter { "TestInput contains a 1" }
        Assert-MockCalled Write-Host -Exactly 1 -Scope It -ParameterFilter { "TestInput contains a 3" }
    }
}

Output

  Describing TestFunction
    [-] should call Write-Host with appropriate message if 1 or 3 is passed 19ms
      at <ScriptBlock>, : line 235
      235:         Assert-MockCalled Write-Host -Exactly 1 -Scope It -ParameterFilter { "TestInput contains a 1" }
      Expected Write-Host to be called 1 times exactly but was called 2 times
Tests completed in 106ms
Tests Passed: 0, Failed: 1, Skipped: 0, Pending: 0, Inconclusive: 0 
Gustative answered 3/3, 2020 at 15:44 Comment(0)
G
16

After reviewing the Microsoft documentation for the Write-Host cmdlet, I found that there is an -Object parameter. This accepts an array of generic objects to write to the console. The -Object parameter is the parameter which needs to be specified in the -ParameterFilter of the Pester tests in order to assert that the appropriate text is being displayed.

My updated code is as follows...

Function to test

function TestFunction($TestInput) {
    if ($TestInput -contains 1) {
        Write-Host "TestInput contains a 1"
    }

    if ($TestInput -contains 3 ) {
        Write-Host "TestInput contains a 3"
    }

    if ($TestInput -contains 4 ) {
        Write-Host "TestInput contains a 4"
    }
}

Pester test

Describe "TestFunction" {
    It "should call Write-Host with appropriate message if 1 or 3 is passed" {
        Mock Write-Host {}
        TestFunction -TestInput @(1, 2, 3)
        Assert-MockCalled Write-Host -Exactly 2 -Scope It
        Assert-MockCalled Write-Host -Exactly 1 -Scope It -ParameterFilter { $Object -eq "TestInput contains a 1" }
        Assert-MockCalled Write-Host -Exactly 1 -Scope It -ParameterFilter { $Object -eq "TestInput contains a 3" }
    }
}

Output

  Describing TestFunction
    [+] should call Write-Host with appropriate message if 1 or 3 is passed 20ms
Tests completed in 99ms
Tests Passed: 1, Failed: 0, Skipped: 0, Pending: 0, Inconclusive: 0 
Gustative answered 3/3, 2020 at 15:44 Comment(2)
-Times 2 -Exactly, also for some strange reason -Scope It only worked correctly for me when It was case sensitive, otherwise it was counting results from other it blocks as wellArioso
If you are mocking a function that is called from within a module, you need to include the -ModuleName when defining the mock. e.g. Mock -ModuleName YourModule Write-Host {}. Mocking Docs: pester.dev/docs/usage/mocking, Module Mocking Docs: pester.dev/docs/usage/modulesEckstein

© 2022 - 2024 — McMap. All rights reserved.