2

So first of all I need to state that I am quite new to Pester and might not be writing my tests correctly or don't properly understand all its functionality.

So background is that I want to automate my PowerShell module with Pester and have written some tests so far.

Part of my module is saving configuration stuff in a clixml file. I would like to write a set of tests to make sure saving and grabbing the configuration works as expected.

Basically I have one function to save the configuration file and one to retrieve it. My Pester test looks as the following:

BeforeAll{
        if(Test-path existingconfigfile.xml){

            Rename-Item -Path "existingconfigfile" -NewName "backup.xml"
        }

        Save-configfunction -param1 'Value1' -param2 'Value2'
        #saves as test.xml
    }

    Afterall{
        if(Test-path backup.xml){

            # Remove mocked test file
            Remove-Item -Path "test.xml" -Force

            # Place original back
            Rename-Item -Path "backup.xml" -NewName "existingconfigfile.xml"
        }
    }

    it "importconfig should return expected values for mocked object" {

        {
            $result = Get-config
            $result
            $result.Containsvalue('Value1') | Should be $true

        }
    }

Now I've tried a couple of variations of the it block:

it "importconfig should return expected values for mocked object" {

        {
            $result = Get-config
            $result.param1 | Should be "Value1"
        }
    }

    it "importconfig should return expected values for mocked object" {
        $result = Get-Config

        $result | Should match 'Value1'
        $result | Should match 'Value2'
    }

    it "importconfig should return expected values for mocked object" {

        $result = Get-Config

        $result.Param1 | Should match 'Value1'
        $result.Param2 | Should match 'Value2'
    }

Pester always returns a passed test even if I change the match values to incorrect ones. Pester does this in all scenarios. So for some reason Pester does not qualify the values correctly and always returns a positive result.

So I'd like to know what I am doing wrong. Obviously Pester should pass the test if the values actually match, but it should fail when they do not match.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tsteenbakkers
  • 264
  • 3
  • 18

1 Answers1

2

I think rather than using BeforeAll and AfterAll to create Mock type behaviour for modifying the config, I would use actual Mock statements. Here's what I mean (I've created simple representations of what I assume your functions do as you haven't shared them):

function Set-Config {
    Param(
        $Config
    )
    $Config | Export-Clixml C:\Temp\production_config.xml
}

function Get-Config {
    Import-Clixml C:\Temp\production_config.xml
}

Describe 'Config function tests' {

    Mock Set-Config {
        $Config | Export-Clixml TestDrive:\test_config.xml
    }

    Mock Get-Config {
        Import-Clixml TestDrive:\test_config.xml
    }

    $Config = @{
        Setting1 = 'Blah'
        Setting2 = 'Hello'
    }

    It 'Sets config successfully' {
        { Set-Config -Config $Config } | Should -Not -Throw
    }

    $RetrievedConfig = Get-Config

    It 'Gets config successfully' {
        $RetrievedConfig.Setting1 | Should -Be 'Blah'
        $RetrievedConfig.Setting2 | Should -Be 'Hello'
    }
}

This creates Mocks of the Get-Config and Set-Config functions that redirect the write/read of the config to TestDrive:\ which is a special temporary disk area that Pester provides and cleans up automatically afterwards.

Note that this only makes sense when testing a parent function that makes use of these functions. If you were writing tests of the Get-Config and Set-Config functions themselves then you'd instead want to be mocking the Export-CliXml and Import-CliXml commands.

Mark Wragg
  • 22,105
  • 7
  • 39
  • 68
  • I'm not sure if i understand your answer but I do realize that my initial question does not give insights to the actual situation. The reason i chose a beforeall / afterall is because my functions for saving and grabbing the config write to a Pre-defined path ($env:appdata\modulename\modulenameconfig.xml). Can i mock this situation as well since your example assumes a path to be entered as a parameter to said functions? Above all i would like to check the actual values stored within the xml file after grabbing the config with my function. is that also possible? – Tsteenbakkers May 19 '18 at 09:56
  • 1
    Yep, and by using a Mock you effectively replace a function with different code. In my example above i'm changing where my Get- and Set-Config functions read and write from to be TestDrive:\ instead of a real path. – Mark Wragg May 19 '18 at 09:58
  • Even if there is a pre-defined path inside said function? Do you have some documentation i can read on mocking? – Tsteenbakkers May 19 '18 at 09:59
  • It doesn't matter that I accept the path as a parameter, but i'll change my answer to have it hard coded in case that helps you. – Mark Wragg May 19 '18 at 09:59
  • Here's the official docs: https://github.com/pester/Pester/wiki/Mocking-with-Pester – Mark Wragg May 19 '18 at 10:00
  • Thanks. I will start reading the documentation and fiddle around with your example. If i need more info i'll ask otherwise i'll mark it as answered – Tsteenbakkers May 19 '18 at 10:06
  • I've amended my answer so that it is writing the configuration that has multiple settings and then checks the value of those settings. – Mark Wragg May 19 '18 at 10:07
  • I've been attempting with Mocks the past days and although i can't fully wrap my head around the functionality yet it does appear that mocking the Save-Config function with a custom Export-Clixml function (and a Test-Path mock) works. Now what i don't get is why pester does fail when expected when i do a manual $results = Import-Clixml $path and then test $results.param1 | should be faultyvalue but it always passes when i do $results = Import-function and then test $results.param1 | should be faultyvalue .... any idea on why it does that? – Tsteenbakkers May 21 '18 at 19:54
  • Maybe update your question with your updated tests and at least the functions being tested. I can’t say why it’s not working based on what you’ve told me. – Mark Wragg May 21 '18 at 19:57
  • I've found the "reason" why it does not throw as expected. In my It block i encapsulated the $results = import-function and the should asserts inside a new set of {} (as shown in my first example with the beforeall / afterall blocks. Apparantly Pester handles extra {} differently and should only be used when you actually want to execute a block of code and assert something like | Should not throw. Not sure if i should raise it as a bug or if it is intended behavior. Thanks for guiding me towards mocks. Going to use them from now on! – Tsteenbakkers May 21 '18 at 20:05
  • You’re welcome. Generally i recommend only putting the assertion inside the it block, any setup/extra code put just before it. – Mark Wragg May 21 '18 at 22:46
  • 1
    Yeah that's what i've been doing sofar. makes for better code in general. I've learned a lot about Pester since i raised this question especially on Mocking. Thanks again – Tsteenbakkers May 22 '18 at 19:59