Search code examples
powershellunit-testingmockingpester

Is there a way to Dispose of a Pester Mock when done with it?


I setup two Mocks in two different It '' blocks for a IIS Method Get-IISSite...

The problem I ran into is those two it's pass, but when I try to do a regular test that doesn't use the mock (its a new 'it' in the same 'context) the method returns the mocks even in separate Its. I read some documentation on another page suggesting that Mocks are available to parent (same context)

This concerns me a bit, because I was hoping to find a mechanism to dispose of the mock once its no longer needed inside the It to restore it. Is it necessary to have non mocks of the same function in a separate describe and or context? (It certainly appears that way)

Code as follows:

Wrote a method to wrap around the empty call to Get-IISSite

### Get all IIS website collection
function IIS-SiteGetAll() {
    $sites = Get-IISSite

    if ($sites.Length -eq 0 -or $sites -eq $null) {
        throw 'No IIS Sites found, please check that IIS is installed and service is running.'
    }

    return $sites
}

Snippet of the Test

Describe 'IIS Site Methods' {
    Context 'IIS-SiteGetAll (mocked)' {

        It 'Throws error if number of sites returned is 0' {
            # Get-IISSite is the Powershell ISS command, we want it to return an empty collection
            Mock -CommandName Get-IISSite { 

                return @()                                
            }             

            { IIS-SiteGetAll } | Should Throw 

        }
        It 'Throws error if number of sites returned is $null' {
            # Get-IISSite is the Powershell ISS command, we want it to return an empty collection
            Mock -CommandName Get-IISSite { 

                return $null                               
            }             

            { IIS-SiteGetAll } | Should Throw 

        }
        It 'Returns collection of sites' { #IIS-SiteGetAll fails because it points to one of the two Mocks in the It above
            $actual = IIS-SiteGetAll

            $actual | Should -BeOfType [Microsoft.Web.Administration.Site]
            $actual.Length | Should -BeGreaterThan 0
        }
    }
    Context 'IIS-SiteGetAll' {            
        It 'Returns collection of sites' { # This separate chain exact same test passes.
            $actual = IIS-SiteGetAll

            $actual | Should BeOfType [Microsoft.Web.Administration.Site]
            $actual.Length | Should -BeGreaterThan 0
        }
    }
}

Note powershell is a bit fuzzy because if you do GetType on actual for the second one it shows as Object[] with BaseType of System.Array (but that fails) only the [Microsoft.Web.Administration.Site] output class seems to work which matches documentation here: https://learn.microsoft.com/en-us/powershell/module/iisadministration/get-iissite?view=win10-ps

I'm not aware of another way around this, but I had to find the answer in a blog, not in Pester's documentation.


Solution

  • Submitting as an answer as OP says it's what he ended up doing:

    Granted I don't normally create a Mock in the It block; I'd do what you have done here and create a separate Context for it.
    There is an AfterEach block you can use in Pester that will run after each It block but you'd need to know how to remove a Mock first to use that...