PowerShell How-To

Using PowerShell Test Case Code with Pester

When testing multiple scenarios to a single test, try this option.

Writing tests for PowerShell code can sometimes be tricky. Depending on how complex your code depends on how many tests that must be created. Also, if you've got a script or function with a lot of parameters, that piece of code can be invoked in many different ways. Since Pester scripts are created using PowerShell, this leaves a lot of flexibility in how the test scripts can be created. Because of this flexibility, accounting for all of the different ways your code can be done some different ways.

To set the stage, let's suppose you have a function with just a single parameter. Below you can see a super-simple function that has a parameter of Name that creates a text file at the root of C but only if it's a particular value.

 

function New-TextFile {
param (
[Parameter()]
[string]$Name
)
if ($Name -eq 'foo') {
New-Item -Path "C:\$Name.txt"
} else {
Write-Output 'Name is not foo'
}


}

Since the Name parameter is a string and has no parameter validation, it can be quite some things. Name could be foo, --, hhh$$$~~~~~// and so on. Apparently, a lot of these examples won't work for a file name. Best practice would dictate adding some validation to the Name parameter but let's pretend we're not doing that for now.

Because it's possible for the Name parameter to contain some different strings, I'll need to create some tests for each scenario. For this example, I'll use Pester's test cases functionality. Test cases work great when testing a function that has various input parameters. For example, in this situation, I'd like to run some tests to ensure my function follows each of the two code paths it has: when Name is foo and when it is not. These are two test cases and be setup like the following:

$testCases = @(
@{
Name = 'foo'
ExpectedObjectType = 'System.IO.FileInfo'
}
@{
Name = 'somethingelse'
ExpectedObjectType = 'string'
}
)

You can see that I have created an array called $testCases that contains two hashtables. Inside of each of these hashtables contains the parameter I'll be passing to New-TextFile as well as an expected result I'll be testing. In this case, I'm checking the object type that's returned, but this can be anything.

These test cases are fed to Pester's it block using the TestCases parameter.

 

it 'should return an object type  of <ExpectedObjectType>' -TestCases $testCases {
param($Name,$ExpectedObjectType)

New-TextFile -Name $Name | should be $ExpectedObjectType
}

Test cases do two things; it allows you to dynamically pass tokens into your it block names by enclosing the value in < and > and it also allows you to send multiple parameters to a single it block without the need for a foreach loop. When using test cases, you'll also need to include a param block for your it block as a way to pass the function parameters as well as the value you'll be testing against.

Bringing all of this code together in a describe block might look something like this:

describe 'New-TextFile' {

$testCases = @(
@{
Name = 'foo'
ExpectedObjectType = 'System.IO.FileInfo'
}
@{
Name = 'somethingelse'
ExpectedObjectType = 'string'
}
)

mock 'New-Item' {
New-MockObject -Type 'System.IO.FileInfo'
}

it 'should return an object type of <ExpectedObjectType>' -TestCases $testCases {
param($Name,$ExpectedObjectType)

New-TextFile -Name $Name | should beoftype $ExpectedObjectType
}
}

PS>
Describing New-TextFile
[+] should return an object type of System.IO.FileInfo 173ms
[+] should return an object type of string 45ms

Once you've got the framework built for test cases, adding additional cases is simple. To add a test case, I'd just add another hashtable to the $testCases array and run my test again. Since the it block will run all cases, there's no need to do anything else.

Test cases are perfect for passing different parameters to a single test and confirming a known result. Next time you have the need to pass multiple scenarios to a single test, don't use a loop. Instead, give test cases a try!

About the Author

Adam Bertram is a 20-year veteran of IT. He's an automation engineer, blogger, consultant, freelance writer, Pluralsight course author and content marketing advisor to multiple technology companies. Adam also founded the popular TechSnips e-learning platform. He mainly focuses on DevOps, system management and automation technologies, as well as various cloud platforms mostly in the Microsoft space. He is a Microsoft Cloud and Datacenter Management MVP who absorbs knowledge from the IT field and explains it in an easy-to-understand fashion. Catch up on Adam's articles at adamtheautomator.com, connect on LinkedIn or follow him on Twitter at @adbertram or the TechSnips Twitter account @techsnips_io.


comments powered by Disqus
Most   Popular