Author Posts

April 8, 2017 at 5:46 am

So I am trying to start using pester more to validate my scripts and I am having a bit of a hard time understanding how to use mock. Here is a quick function I put together and the tests. I am trying to mimic a function that gets an Aduser and throws an error if user is not found.
#### Function

function Set-DomainAduser
{
    [CmdletBinding()]
    Param
    (
        # Param1 help description
        [Parameter(Mandatory=$true,
                   ValueFromPipelineByPropertyName=$true,
                   Position=0)]
      [string]  $User)

    Begin
    {
    }
    Process
    {
        try {
          $user =   Get-ADUser $User
          if ($user) {
              return $User
          }
        }
        catch {
            throw "$user not found in AD Domain"
        }
    }
    End
    {
    }
}

## Test

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"

Describe 'Test AdUser' {
	Context 'Return AdObject' {
		Mock -CommandName 'Get-aduser' -MockWith {return @{name ='here'} }
		it 'Should return ADObject' {
			Set-DomainAduser 'me' | should be @{name ='here'} 
			}
		}
	}
}

Here is the output

 
Context Return AdObject
      [-] Should return ADObject 211ms
        Expected: {System.Collections.Hashtable}
        But was:  {System.Collections.Hashtable}

Am I approaching the mock function correctly?

April 11, 2017 at 6:59 pm

Hi James,

I am also on this journey learning DSC along with Pester. I was trying to learn/understand how to utilize Mocking within my Unit testing. Looking at your cod you have to mock the function and not the cmdlet within it. I also removed your Explicit Parameters within your function because when I ran the test and tried to mock the values out, it still expected the parameters. I believe there is a way to avoid this, but I am unaware at the moment. Anyhow I updated your tests with some Mock data to return. I believe since these are expected to be unit testing, you mock out the expected responses for your function and if that changes in the future so does your tests. When you create Integration testing, then you would actually pass in valid data.

Not sure if this helps any. Good luck!

## Set-DomainAdUser.ps1 script
#### I removed your Mandatory and Position parameters. #######
function Set-DomainAduser {
    [CmdletBinding()]
    Param
    (
        [string]
        $User
    )
    Begin {
    }
    Process {
            try {
                    $user = Get-ADUser $User
                    if ($user) {
                        return $User
                    }
            }
            catch {
                throw "$user not found in AD Domain"
            }
    }
    End {
    }
}
#Set-DomainAdUser.Tests.ps1

$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"

#### I had to specifiy the exact location of this script/module since it was in one of my $PsModulePath's ########
Import-Module  -Name "C:\Temp\PesterTests\Set-DomainAdUser.ps1" -verbose

Describe 'Test AdUser' {
    $mockdata =
        @{
            Name = "here"
        }
    Context 'Return AdObject' {
######## Mock out the function name and not the cmdlet within the function like you did in your previous thread ######
        Mock -CommandName Set-DomainAduser -MockWith { return $mockdata }
        $result = Set-DomainAduser
        it 'Should return ADObject here' {
            $result.Name | Should Be "here"
        }
    }
}