Pester in practice

The following function sets a computer description by modifying values in the registry:

function Set-ComputerDescription { 
    [CmdletBinding()] 
    param ( 
        [Parameter(Mandatory = $true)] 
        [AllowEmptyString()] 
        [String]$Description 
    ) 
 
    $erroractionpreference = 'Stop' 
 
    try { 
        $path = 'HKLM:SystemCurrentControlSetServicesLanmanServerParameters' 
 
        if ((Get-Item $path).GetValue('srvcomment') -ne $Description) { 
            if ($Description) { 
                Set-ItemProperty $path -Name 'srvcomment' -Value $Description 
            } else { 
                Clear-ItemProperty $path -Name 'srvcomment' 
                Remove-ItemProperty $path -Name 'srvcomment' 
            } 
        } 
    } catch { 
        throw 
    } 
} 

When the function interacts with the registry, it does so using the following commands:

  • Get-Item
  • Set-ItemProperty
  • Clear-ItemProperty
  • Remove-ItemProperty

Testing the actions undertaken by each of the previous commands is not the responsibility of a unit test for Set-ComputerDescription. The unit tests are limited to ensuring that each of the commands is with the right parameters and at the right time. Each of the previous commands will be mocked.

The function reacts to a combination of the value of the Description parameter and the current state of the value.

A set of context blocks is appropriate for this division of the test. The difference between the blocks is the response from Get-Item and is therefore the implementation of the Mock:

Describe Set-ComputerDescription { 
    Mock Set-ItemProperty 
    Mock Clear-ItemProperty 
    Mock Remove-ItemProperty 

The first context is used to describe what happens when the current description is blank. A Mock for Get-Item is created, which returns a blank result:

    Context 'Description is blank' { 
        Mock Get-Item { 
            [PSCustomObject]@{} | Add-Member GetValue -MemberType ScriptMethod - 
Value { return '' } }

Each of the subsequent tests will use the Get-Item mock. These tests do not explicitly verify that Get-Item was called; it is perhaps unnecessary, as it sits in all possible code paths (except an error prior to it being called):

        It 'Updates the description with a new value' { 
            Set-ComputerDescription -Description 'New description' 
            Assert-MockCalled Set-ItemProperty -Scope It 
        } 
 
        It 'Does nothing if the description has not changed' { 
            Set-ComputerDescription -Description '' 
            Assert-MockCalled Set-ItemProperty -Times 0 -Scope It 
            Assert-MockCalled Clear-ItemProperty -Times 0 -Scope It 
            Assert-MockCalled Remove-ItemProperty -Times 0 -Scope It 
        } 
    } 

The previous tests may be enhanced to ensure that Clear and Remove-ItemProperty are not called when updating with a new value. Given that the code paths are mutually exclusive, this is unlikely to be necessary.

The next context tests the actions that should be taken if a description is set. The Mock for Get-Item is replaced with one which returns a value:

    Context 'Description is set' { 
        Mock Get-Item { 
            [PSCustomObject]@{} | Add-Member GetValue -MemberType ScriptMethod -Value { 
                return 'Current description' 
            } 
        } 

The next set of tests explores the possible actions, which may result in changing the description in this state:

        It 'Updates the description with a new value' { 
            Set-ComputerDescription -Description 'New description' 
            Assert-MockCalled Set-ItemProperty -Scope It 
        } 
 
        It 'Does nothing if the description has not changed' { 
            Set-ComputerDescription -Description 'Current description' 
            Assert-MockCalled Set-ItemProperty -Times 0 -Scope It 
            Assert-MockCalled Clear-ItemProperty -Times 0 -Scope It 
            Assert-MockCalled Remove-ItemProperty -Times 0 -Scope It 
        } 
 
        It 'Clears a description' { 
            Set-ComputerDescription -Description '' 
            Assert-MockCalled Clear-ItemProperty -Times 1 -Scope It 
            Assert-MockCalled Remove-ItemProperty -Times 1 -Scope It 
        } 
    } 

The preceding tests might be enhanced to verify that an error will trigger the catch statement. For example, if Set-ItemProperty were to throw a non-terminating error with ErrorActionPreference set to Stop, a non-terminating error would be raised as a terminating error. The terminating error can be tested:

Mock Set-ItemProperty { Write-Error -Message 'Non-terminating error' } 
 
It 'Throws a terminating error if a terminating or non-terminating error is raised' { 
    { Set-ComputerDescription -Description 'New description' } | Should Throw 
} 

The previous test will need to be placed in such a context that Set-ItemProperty is called. For example, this test might appear at the end of the first context block.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.201.217