Search code examples
unit-testingpowershellpester

Pester BoundParams in CallHistory empty


I have a simple that at this point doesn't do anything, I am just getting started with Pester, but my goal is to mock Remove-ADGroupMember and a few other AD powershell commands for testing.

Param(
  [string]$computerList = ".\\computers.csv",
  [boolean]$isTest = $false
)

function Remove-Groups(){
  Remove-ADGroupMember -Identity "dale" -Members "dale","cameron"
}

and my test script

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = "../" + (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$here\$sut"

Describe "UninstallUnused - Remove-Groups" {
    It "does something useful" {
      Mock Remove-ADGroupMember
      Remove-Groups
      Assert-MockCalled Remove-ADGroupMember -Exactly 1
      Assert-MockCalled Remove-ADGroupMember 1 -ParameterFilter {$Identity -eq "dale" -and $Members -contains "dale"}
    }
}

The First Assert-MockCalled line works, but no matter what I try on the second one the tests always fails. After awhile I dug into the Assert-MockCalled funciton with a debugger and it looks like the values of the -Members parameter are getting lost

enter image description here

In the picture above I'm in the Assert-MockCalled function of Mock.ps1 and as you can see the values passed to members are missing. If I only pass 1 value to the Remove-ADGroupMember mock like so: Remove-ADGroupMember -Identity "dale" -Members "dale" the value I see in BoundParams is {} instead of {, } as you see in the screenshot.

Is this an issue with the way I'm doing it or is the problem the way the pester is reading the params etc. from Remove-ADGroupMember?


Solution

  • The Identity nor the Members parameters are of type String, so that's why your assertions do not work.

    • Identity - Microsoft.ActiveDirectory.Management.ADGroup
    • Members - Microsoft.ActiveDirectory.Management.ADPrincipal[]

    So in order to make the filter work you need to cast to string (the types luckily serialize to the names you need)

    function Remove-Groups(){
      Remove-ADGroupMember -Identity "dale" -Members "dale","cameron"
    }
    
    Describe "UninstallUnused - Remove-Groups" {
        It "does something useful" {
          Mock Remove-ADGroupMember
          Remove-Groups
          Assert-MockCalled Remove-ADGroupMember -Exactly 1
          Assert-MockCalled Remove-ADGroupMember 1 -ParameterFilter {
            Write-Host ( $identity.GetType(),$members.GetType()) ; #otputting the data types
            ([string[]]$members) -contains "dale" -and ([string]$identity) -eq "dale" }
        }
    }
    

    Edit: You could also use the automatic casting to the left parameter, but that makes the code easier to break:

     ([string[]]$members -contains "dale") -and ("dale" -eq $identity)