Practical PowerShell Unit-Testing: Getting Started

Comments 0

Share to social media

Contents

PowerShell has grown up. In its recent versions, there are few things that PowerShell  applications aren’t capable of doing just as easily as a more traditional language, plus a myriad of tasks that it can do better. It particularly shines at automating routine tasks. And even for these, there is a lot of sense in being able to do automated unit testing when developing and modifying scripts. This isn’t just a developer obsession: anyone who is writing scripts that must be reliable can do it faster, and with less tedium, by putting in place a safety net of unit tests. Unit tests provide maintainability (allowing you to make changes knowing that you have not broken anything), documentation (the tests show you and your colleagues how to use your scripts), and robustness (writing test cases is a good way to find holes in your logic)  . And with the recent advent of unit testing frameworks now available for PowerShell, it is easier than ever to get started. When I  needed to  do this, I  looked around at the handful of nascent unit testing frameworks available and quickly settled on Pester, the subject of this article.

It is important to have a good grasp of the mechanics of unit tests in PowerShell.  As with many developer tools, frameworks, etc., you have some reference material provided with the product, and you have some usage examples, but what it lacks is a practical, no-nonsense description of how to use the thing. So, what you will find herein is what I like to call “tips from the trenches”: a collection of user tips, techniques, and tools accumulated and developed through hard-fought battles, which I can relate to you here so that you do not have to struggle with the same issues. I’m hoping that this will significantly reduce the Pester learning curve for you.

Pester has, to be fair, made my task slightly less urgent. Pester 3.0 was just released; besides , by adding some new functionality they also fixed a couple of issues  that I now no longer need workarounds for: Pester, for example,  now supports PowerShell’s ‘strict’ mode), so I definitely recommend  the 3.0 release.

Hello, World, Pester-Style

Before getting into the details, though, let’s take a look at how to write a unit test with Pester. Almost everything in this section is explored in more detail throughout the remainder of this series, but let’s  start with the canonical “Hello, World”. See the next section Executing Tests for instructions on installing and importing the Pester library, but if you have PSGet installed, it is as simple as  typing Install-Module Pester to download and install the pester package and then Import-Module Pester at the start of the script to load it into the current session.

Step 1: Create a subdirectory for your PowerShell program.

The next step, that of creating a file to hold your source code (HelloWorld.ps1) and a file to hold your test code (HelloWorld.Tests.ps1), is done automatically  by executing  the following –

You will see that Pester has checked to see if the files exist and, as they have  not, has created these two  files, HelloWorld.ps1 and HelloWorld.Tests.ps1 for you, and put in sufficient skeletal code to run the unit test, so let’s just invoke Pester to test the empty function:

The first test was expecting to see false but saw true, so the test failed. If you open the test file HelloWorld.Tests.ps1, you will see what I call the file preamble, which I will ignore for now (described later under Test Anatomy), followed by the actual test which should be this:

In a nutshell, the Describe command specifies the name of the function under test and the It command specifies a single test. The content of that test is the single line of code shown that maps to this syntax:

actual-value | Should Be expected-value

Want to see what a passing test looks like? Change the actual value to $false (or the expected value to $true), then run it again.

Now let’s write some real code, something that actually invokes the function in the source file. Open the source file and you will find an empty function:

Let’s change it to simply return a phrase:

And now let’s write a test that confirms that return value; I am just going to add this as a second test so you can see how a Describe block may contain several  tests.  We leave the preamble in place

Notice also that I changed the original dummy test expect $true, so both tests should pass when you execute invoke-pester: