Going forward in the Devops world, you will sooner or later end up asking yourself the following questions:
I made a change to my code, does it still work? How can I ensure that the changes I made didn’t break anything?
You could hard code some values and hit F5 of course. It might work for that one particular case, but are you sure it will work for all the other ways it exists to call you code? Pipeline input, exports, file creation etc… Will all the parameters still work as expected? Will the script fail when it has to fail? You can’t say for sure, if you have not a test script that will test your code. Can you trust a modification that someone else did on your function? In other languages they use testing frameworks, to test how well the code works. The same tests are called after each change, and guarantee the code still works. We didn’t had anything for a while in that direction, but Luckily there is Pester for PowerShell. A unit testing framework for windows PowerShell.
This blog post is part 1 of a series of 3 posts to learn how to write PowerShell pester test. In this blog post we will cover the fundamentals of pester in part 1, we will deep dive into the code and learn the details about the pester syntax in part 2 which will give us enough amo to shoot our first pester tests. In part 3 of this series, we will tackle the advanced concepts of pester tests and talk about some of pesters features that allows us to control better the information resulting from our pester tests, such as which test failed, which one didn’t etc…
These blog posts follow each other, but can be read seperatley. The three blog posts will bring you from zero to hero in no time!
The scripts that are used through out this series about pester test are available on github here. The scripts for part one are located under the folder named part1.
Say ‘Bonjour’ to Pester
What is pester for PowerShell, and why should we use it?
Bonjour Pester!
PowerShell Pester is what we call a unit test framework. It is an open source project located on GitHub. Pester is available with Windows 10. Although PowerShell pester is designed to test PowerShell scripts only, it’s syntax is a bit different from the original PowerShell syntax. The syntax being what is, I have to confess that it kind of threw me off in the very beginning. But you will see, it is quite easy, and the learning curve is not so steep after all. In the end you can write some very robust pester tests knowing just a few things of powershell pester.
So, why would you even want to write pester tests for Powershell?
The answer is pretty simple: “Quality“. Writing a PowerShell pester test for your script, will ensure that when you modify it, it won’t break. And in case you actually do, you be noticed that you broke it, and can fix it accordingly.
Write powershell pester tests to improve the overall quality of your code, and to find & fix bugs before your users do.
On a bigger picture, pester is also one of the key component in continuous integration scenarios. The idea is that if you add a change to existing code, and call your pester tests. If the tests are successful, you could call another other script that would deploy the first script directly into production, provision servers etc… only your imagination will limit you here.
So, writing powershell pester tests brings you a few advantages:
- It ensures the quality of your code over the different changes it will face.
- Increase how fast we can implement changes.
- Gives us the possibility to switch our way of coding, and start a test driven development approach.
- Brings us a step closer to continuous integration scenarios.
Learning by doing: Our PowerShell pester Test case
Instead of listing every parameter and option that PowerShell pester has to offer and explaining them, I think it is easier to learn something new by directly starting using it. It gives a better visibility on the gains of the technology solves and the the problems that it helps to solve.
We will write our pester tests for a function that is pretty ‘popular’ if I can say so. The function is from one of the presentations of “Don Jones”.
I like this example, because that was probably one of the first that I looked at, and one that learned me the basics of writing a functions. It has some nice extra functionality (pipeline input etc…) so everything we need in ordrer to write our first pester test 🙂.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
Function Get-ComputerInfos {
[cmdletbinding()]
Param(
[ValidateNotNullOrEmpty ()]
[parameter(Mandatory=$false,ValueFromPipeline=$True,ValueFromPipelinebyPropertyName=$True)]
[string[]]$computername=$env:COMPUTERNAME
)
$Objects = @()
Foreach ($Computer in $ComputerName){
if (Test-Connection -ComputerName $computername -Count 1 -Quiet){ #<– Added Test-Connection in IF block
Write-Verbose “working on $ComputerName”
$Infos = Get-CimInstance -Class win32_operatingSystem -Property OSArchitecture,LastBootUpTime,TotalVirtualMemorySize,Caption,servicepackmajorversion -ComputerName $Computer
$Properties = @{}
$Properties.Add(“ComputerName”,$Computer)
$Properties.Add(“Architecture”,$Infos.OSArchitecture)
$Properties.add(“LastBoot”,$Infos.LastBootupTime)
$Properties.Add(“OSversion”,$Infos.Caption)
$Properties.Add(“TotalMemorySize”,$Infos.TotalVirtualMemorySize)
$Properties.Add(“SPversion”,$Infos.servicepackmajorversion)
$object = New-object -TypeName psobject -Property $Properties
$Objects += $object
}else{
write-warning “Computer $($Computer) not available”
$Properties = @{}
$Properties.Add(“ComputerName”,$Computer)
$Properties.Add(“Architecture”,“”)
$Properties.add(“LastBoot”,“”)
$Properties.Add(“OSversion”,“”)
$Properties.Add(“TotalMemorySize”,“”)
$Properties.Add(“SPversion”,“”)
$object = New-object -TypeName psobject -Property $Properties
$Objects += $object
}
}
return $Objects
}
|
Defining the critical elements of our existing code
In this section, we want to identify the crucial parts of our function that we want to test.
There is some functionality that we could make really robust against code change using just a few lines of pester, and guarantee a high quality of our code.
- Should Accept Pipeline Input
- Catches if PC not existing
- Catches if PC not reachable
- Missing rights
- ComputerName Parameter is empty or null
- ComputerName Parameter is of wrong type.
- If the computer is not available, it should return an empty object
- Script should always return a customObject with the following informations:
- Memory
- Architecture
- Last Boot Time
- Computer name
- Os version
- Service Pack version
Getting our environment ready: How to install PowerShell pester?
Depending on the system that you are running, If you have PowerShell 5.0 or higher installed, you already have everything you need, and you can jump directly to the next section.
If it is not the case, you can get pester in the following two ways:
- The most forward and easiest way is to use the Package Management calling the following command from an elevated prompt:
Find-Module “Pester” | install-module
But If you are behind a corporate proxy this could get a bit complicated. You can try the two other methods here under.
- Download the code as Zip on the powershell pester github page.
Go to the Pester Gibhub Page here, right click on the right “Download as Zip” and save it to a known location. Unblock the zip file (using unblock-file) and extract the data to your module folder (Usually that is ‘ C:Program FilesWindowsPowerShellModules’
- Forking the repository on Github
This step is not that complicated, but it can be a bit confusing especially if you are not used to using git and github. This would be the method to follow if you want to participate in the open source project. You can easily make changes, and submit a pull request.
How to write PowerShell pester tests?
Our first powershell pester test
What is a pester test actually? It is a script, that will test a script or a function that we wrote. The Pester test must be linked to a script, or module. The following convention is generally applied to the naming of pester test scripts:
<ScriptName>.Tests.ps1
So, in our case, our Script is called “Get-ComputerInfo.ps1” so the according pester tests have to be written a file named as follow: “Get-ComputerInfo.Tests.ps1”
The naming convention .tests.ps1 is actually not mandatory. Even though it isn’t, I would recommend to keep it like this, because first it makes sense, and everybody is already used to this naming convention anyways.
Using New-Fixture
New-Fixture is a cmdlet that is shipped within the pester module. It allows us to pre-create an empty script together with an empty test file. It is the fastest way to get you started from scratch.
To create our first PowerShell pester test, it is as easy as calling New-Fixture like this:
New-Fixture -Path . -Name PesterSeries
The results are the following:
You can see that New-Fixture creates two files:
PesterSeries.Ps1 Which contains a basic script that we can use to start scripting Which actually contains the following empty function:
PesterSeries.Tests.Ps1 Our Pester test script. Which contains the following 9 lines of code
So an empty function and a pester test that goes with it.
I personally create my own pester test, and use new-Fixture quite seldom.
Omiting the two lines that set the current path, what do we have here?
A Describe block, an IT block, and a test.
I will go in detail in each block later in this series, but for now, you need only to know the following things:
Describe:
Think of the describe block (in yellow), of a way of regrouping several tests into a same block, and giving it a name. You can think of it as an “Advanced #region” if you want.
IT:
The IT block (in green) is the block that will actually contain our test.
Should:
The whole mechanism of Pester resides in the piping actions to the “Should” keyword (Blue part). The expression is then evaluated, and the test will be either successful and display a nice green message, or it will fail and it will display in red the reason why it failed.
You will see also some purple which is mostly used to describe what the test is actually doing.
But don’t worry, we will see almost everything around PowerShell pester in this blog series.
How to Call a PowerShell Pester test
Now that we have created our first PowerShell Pester test, let’s run it. This can be done in two different ways:
- If you use the ISE, simply press F5
- In a powershell prompt, navigate to the folder where your script is located, and run invoke-Pester
In Both ways it will return the same result as showed on the picture above.
Don’t worry, the red part is actually a good thing. The test we generated failed, and that is actually what it was supposed to do.
Remember, we want to write pester tests to make our scripts more robust. Therefore, when a test fails, it means that the test allowed us to identify a case that has not been taken into consideration until now during the development of our script, and that we can adapt our code to handle this behavior correctly.
Pester’s syntax is self-comprehensive, and anyone that knows how to read (and understands English) will understand (more or less) what your test is doing.
It should be $false but it received a $true.
$true | Should Be $false
If we replace $False with $true and call invoke-Pester again, all our tests will succeed as showed in the screenshot below.
$true | Should Be $true
New-Fixture created a nice and quick to use pester template. We actually don’t have to use new-fixture to create our pester test, and to be honest, most of the time, I create mine from scratch. It is pretty straight forward.
That’s all for today folks. Tomorrow, we will go into depth on all the various blocks that pester contains, and we will write our second pester test, this time concerning our function from above.
Leave A Comment