
Sergey Nivens - Fotolia
Pester PowerShell unit testing ensures quality code
PowerShell jockeys can turn to the Pester unit testing framework to ensure the code they write is up to snuff.
PowerShell is not just for quick, ad hoc tasks anymore -- it underpins the configuration of entire IT estates -- and one bad line can disrupt the deployment of systems and applications.
PowerShell's evolution from a fledgling scripting language into a full-featured automation tool makes it a must for any administrator's toolbox. Large organizations increasingly rely on PowerShell to provision virtual environments, manage critical code deployments and orchestrate many other business-critical tasks.
This increased reliance on PowerShell requires IT to ensure scripts' reliability. This is where Pester, a PowerShell unit testing framework, can help. Pester tests how PowerShell scripts execute before they reach live systems. It's the only PowerShell testing framework available. It's important enough that Microsoft packages Pester in Windows Server 2016 and Windows 10.
Build a script for PowerShell unit testing
Pester enables users to write simple PowerShell unit tests for scripts of varied complexity. For example, an administrator wrote a script that provisions virtual machines for the fictional Acme company, and names the script New-AcmeVm.ps1. The first part of the script creates a Microsoft Hyper-V VM with various attributes. A key piece of the script determines what name to assign to the VM, such as SRV1, SRV2, SRV3 and so on, or a different naming convention.
The script assigns the server name with the next available number when it creates a new VM. This part is crucial for the rest of the script to finish successfully. A sample of that script looks like:
function Get-VmName {
param()
## Find existing VMs
$existingVms = Get-Vm
## Get the new VM's number
$number = $existingVms.Name | foreach {
$_ -replace '^SRV'
} | Sort-Object –Descending | Select –First 1
## Return the name
"SRV$([int]$number + 1)"
}
Time to pester PowerShell with tests
Microsoft packages Pester in Windows 10 and PowerShell 5. Administrators can also download Pester with the Find-Module –Name Pester | Install-Module command.
Pester unit tests are PowerShell scripts with an optional -- yet recommended -- naming convention. In Figure 1, a command in Pester called New-Fixture creates the testing template:
New-Fixture –Name New-AcmeVM.
This builds the script and a tests file.

Replace the New-AcmeVM.ps1 script with the script created earlier in this tutorial. The tests template file should look like this:
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
$sut = (Split-Path -Leaf $MyInvocation.MyCommand.Path) -replace '\.Tests\.', '.'
. "$here\$sut"
Describe "New-AcmeVm" {
It "does something useful" {
$true | Should Be $false
}
}
Replace the existing describe block with a fitting description:
describe 'New-AcmeVm' {
it 'calculates the right VM name and passes it to the New-VM command' {
Get-VmName
}
}
Powershell unit testing shows what you've got
Pester consumes tests in PowerShell script blocks, which are statements or expressions compiled into a unit to take arguments and return values.
The parent block is always the Describe block. This is a parent container for individual PowerShell unit tests. Inside the describe block, add some Pester tests with the It blocks. It blocks contain the PowerShell code that validates the code the administrator wants to test. It blocks are logical groups of code that separate different functionality. In this example, there is just a single It block because the only test is to verify that the VM is named correctly.
Next, use a Pester mock, which is a way to create fake dependencies and check behavior, to test the script with the following:
describe 'New-AcmeVm' {
mock 'Get-Vm' {
[pscustomobject]@{Name = 'SRV1'}
}
it 'calculates the right VM name and passes it to the New-VM command' {
Get-VmName | should be 'SRV2'
}
}
The mock "overwrites" the original Get-VM command to return a single object that represents a test sample of VM names. The mock also has an assertion to test the result of Get-VmName. Run the test with the following command to see the result:
Invoke-Pester -path C:\New-AcmeVM.Tests.ps1

Figure 2 shows the test is a success -- when the script with the Get-VmName function runs, it will always return the correct name.