Search code examples
azurepowershellunit-testingmockingpester

How to mock Azure PowerShell Cmdlets in Pester?


So I've been trying to unit test my Azure deployment script and not been able to mock the Azure cmdlets. Even with the mocks in place they are executed during the tests.

This is my PowerShell Version.

Name                           Value
----                           -----
PSVersion                      5.1.16299.1146
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.16299.1146
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

And im on Version 4.8.1 of Pester.

So this is what my actual code looks like, that i was trying to get to work. First the function:

function CleanUp-Resources {
    Set-AzContext $DeploymentSubscriptionName | Out-Null
    $resGroup = Get-AzResourceGroup -Name $script:devtestlabRGName -ErrorAction SilentlyContinue
    if (!$resGroup) {
        $Global:Error.RemoveAt(0)
    }
    else {
        Write-SitAzLog "Removing resource group and all generated resources"
        Remove-SitAzRGWithLocks $resGroup.ResourceGroupName
    }
}

As you can see it's just a simple function to remove a resourceGroup if it exists.

Now the test code:

Describe "CleanUp-Resources" -Tags "Disabled", "Unit"{
    Mock Write-SitAzLog {} 
    Mock Set-AzContext {} 


    Context "res group not found" {
        $cnt = $Error.Count
        Mock Get-AzResourceGroup {
            throw "Not found"
        }
        It "deletes the error message from count" {
            CleanUp-Resources
            Assert-MockCalled Get-AzResourceGroup 
            $Error.Count | Should Be $cnt
        }
    }
}

So my understanding of mocking is that this should stop the actual Set-AzContext function from being run as it is mocked with an empty script block. But unfortunately the Set-AzContext throws an error that the value for parameter context is null, which shows that it's trying to execute the normal cmdlet. Mocking cmdlets from other modules worked just fine so I'm guessing it has somethoing to do with the Azure module in particular.

Ty for any feedback.


Solution

  • The working solution for me is to provide some (mocked) input to the mocked command - without it, mock is not hit.

    Code:

        $subscription = Get-AzSubscription -SubscriptionId 'xyz'
    if ($null -ne $subscription) {
        Set-AzContext -SubscriptionObject $subscription | Out-Null
    }
    

    Mock:

    Mock Get-AzSubscription -ParameterFilter {$SubscriptionId -eq 'xyz'}{
        return New-Object Microsoft.Azure.Commands.Profile.Models.PSAzureSubscription
    }
    Mock Set-AzContext
    

    and in this case both mocks are hit. Without an object returned from Get-AzSubscription, Set-AzContext mock is not hit and pester returns error.