Unit Testing using Pester
Pester is the TDD style unit testing framework for PowerShell
Advantage of using pester
- It can be integrated into the build scripts of a Continuous Integration system.
- Unit Tests are written in PowerShell and also contains a powerful set of Mocking Functions
We will see how to install pester , commands in pester and how to write basic tests in pester
Installing Pester
We will use visual studio 2013 for writing tests. First install the extensions “PowerShell tools for visual Studio 2013″ as shown
Create a new powershell script project called “PowerShellProject” as shown.
Add another powershell script project called “PowerShellProjectTest” to the solution. The project structure will be as shown.
Run the command “Install-Package Pester” in Package Manager Console as shown.
**
Pester commands:** Following are the commands commonly used while writing tests.
- Describe: Creates a logical group of tests
- Context:Provides logical grouping of It blocks within a single Describe block
- It:Validates the results of a test inside of a Describe or Context block.
- Should:Should is a command that provides assertion convenience methods for comparing objects and throwing test failures when test expectations fail. Should is used inside It blocks of a Pester test script.Following are the operators which are self explanatory used with Should
- Should Be Greater Than
- Should Be
- Should Be Less Than
- Should Be NullOrEmpty
- Should Contain
- Should Exist
- Should Match
- Should Throw
- Should Not Be
- Should Not BeNullOrEmpty
- Should Not Contain
- Should Not Exist
- Should Not Match
- Should Not Throw
- BeforeEach and AfterEach:The BeforeEach and AfterEach commands allow you to define setup and teardown tasks that are performed at the beginning and end of every It block
- In:A convenience function that executes a script from a specified path.
- Mock:Mocks the behavior of an existing command with an alternate implementation.
- Assert VerifiableMocks:Checks if any Verifiable Mock has not been invoked. If so, this will throw an exception.
- Assert MockCalled:Checks if a Mocked command has been called a certain number of times and throws an exception if it has not.
- InModuleScope:The InModuleScope command allows you to perform unit testing on the internal (non-exported) code of a Script Module.
Create Unit tests
Create the files Demo.ps1 and Demo.psm1 in PowerShellProject project and create Demo.Tests.ps1 in PowerShellProjectTest Project
First Test: Add the code to Demo.Tests.ps1 file.This test checks for a simple boolean value
$scriptDirectory = (Split-Path -Parent $MyInvocation.MyCommand.Path) -replace "Test$"
$scriptName = (Split-Path -Leaf $MyInvocation.MyCommand.Path).Replace(".Tests.", ".")
. "$scriptDirectory\$scriptName"
Describe "HelloWorld" {
It "does something useful" {
$true | Should Be $true
}
}
Second Test:Add the code to Demo.ps1 file. This test will mock the Get-ChildItem powershell cmdlet.
function Get-TextFileNames() {
Get-ChildItem | Where Name -like *.txt | Select -expand Name
}
Add the following code to Demo.Tests.ps1 file. We will use the Mock command to provide our own implementation.
Describe 'TextFileName' {
It 'returns one text file' {
Mock Get-ChildItem { [PSCustomObject]@{ Name = 'a923e023.txt' } }
Get-TextFileNames | Should Be 'a923e023.txt'
}
}
Third Test:Running tests for the functions in powershell module.Add the following code to Demo.psm1 file.This test will mock the dummy functions “Get-Version” and “Get-NextVersion” defined in a powershell module
function VersionIfChanged {
$thisVersion = Get-Version
$nextVersion = Get-NextVersion
if ($thisVersion -ne $nextVersion)
{
return $nextVersion
}
else
{
return $thisVersion
}
}
function Get-Version { return 0 }
function Get-NextVersion { return 0 }
Export-ModuleMember -Function VersionIfChanged
Add the following code to Demo.Tests.ps1 file.We will use the Mock command to provide our own implementation.
Import-Module $scriptDirectory\Demo
Describe "VersionIfChanged" {
Context "When there are Changes" {
Mock -ModuleName Demo Get-Version { return 1.1 }
Mock -ModuleName Demo Get-NextVersion { return 1.2 }
$result = VersionIfChanged
It "returns the next version number" {
$result | Should Be 1.2
}
}
Context "When there are no Changes" {
Mock -ModuleName Demo Get-Version { return 1.1 }
Mock -ModuleName Demo Get-NextVersion { return 1.1 }
$result = VersionIfChanged
It "Should not be the next version" {
$result | Should Be 1.1
}
}
}
Run all the tests in test explorer as shown.