Why Pester Matters
In the world of DevOps and automation, it’s crucial that your code - you know, the thing that enables your automation - be reliable. In the past, you’d accomplish reliability, or attempt to, by manually testing your code. The problems with manual testing are legion:
- You’re likely to be inconsistent. That is, you might forget to test some things sometimes, which opens the door to devastating bugs.
- You’re going to spend a lot of time, if you’re doing it right (and the time commitment is what makes most people not “do it right” in the first place).
- You end up wasting time setting up “test harnesses” to safely test your code, amongst other “supporting” tasks.
This is where Pester comes in. Simply put, it’s a testing automation tool for PowerShell code, as we explained earlier in this book.
- Pester is consistent. It tests the same things, every time, so you never “miss” anything. And, if you discover a new bug that you weren’t testing for, you can add it to your automated tests to make sure that bug never “sneaks by” again.
- Pester can be automated, so it takes none of your time to perform tests.
- Pester integrates well with continual integration tools, like Visual Studio Team Services (VSTS), Jenkins, Team City, and so on, so that spinning up test environments and running tests can also be completely automated.
The vision goes something like this:
- You check in your latest PowerShell code to a code repository, like Git or VSTS. That code includes Pester tests.
- A miracle occurs.
- Your tested code is either rejected due to failed tests (and you’re notified), or your code appears in a production repository, such as a NuGet repository where it can be deployed via PowerShellGet.
The “miracle” here is some kind of automated workflow. VSTS, for example, might spin up a test environment, load your code into it, and run your Pester tests against your code. We’re not going to cover how to make the miracle work, as it’s not technically a PowerShell thing per se, and because there are so many combinations of options you could choose. We are going to focus on how to write those Pester tests, though.
The big thing here is that you need to be writing testable code, a concept we’ll devote a specific chapter to. But if you’re looking for the short answer to, “What is testable code?” It’s basically “follow the advice we’ve been giving you in this book.” Write concise, self-contained, single-task functions to do everything.
The other thing you’ll want to quickly embrace is to write your Pester tests immediately, if not actually in advance of your code (something we’ll discuss more in the chapter on test-driven development). This is going to require an act of will for most PowerShell folks because we tend to want to just dive in and start experimenting, rather than worrying about writing tests. But the difference between the adults and the babies, here, is that the adults do the right thing because they know it’s the right thing to do. Having tests available from the outset of your project is how you reap the advantages of Pester, and indeed of PowerShell more generally.
So that’s why Pester is important. We don’t think anyone should write any code unless they’re also going to write automated tests for it.
It’s also important to understand what Pester does, and this gets a bit squishy. First, it’s worth considering the different kinds of testing you might want to perform in your life. Here are a few testing patterns but by no means all:
-
Unit testing is nothing more than making sure your code runs. You want to make sure it behaves properly when passed various combinations of parameters, for example, and that its internal logic behaves as expected. You usually try to test the code in isolation, meaning you prevent it from making any permanent changes to systems, databases, and so on. You’re also just testing your code, not anybody else’s. If your code internally runs
Get-CimInstance, then you prevent it from doing so, sinceGet-CimInstanceisn’t your code. Unit testing is what Pester is all about, and it contains functionality to help you achieve all of the above. The idea is to isolate your code as much as possible to make testing more practical, and to make debugging easier. -
Integration testing is a bit more far-reaching. It’s designed to test your code running in conjunction with whatever other code is involved. This is where you’d go ahead and let internal
Get-CimInstancecalls run correctly, so make sure your code operates well when integrated with other code. Integration testing is more “for real” than unit testing, and typically runs in something close to a production environment, rather than in isolation. - Infrastructure validation can be thought of as an extension of integration testing. Because so much of our PowerShell code is about modifying computer systems, such as building VMs or deploying software, infrastructure validation runs our code and then reaches out to check the results. Pester can also be used for this kind of testing, and we’ll get into it more later in this book.
All of this is important to understand because it helps you better understand what a Pester test looks like. If you’ve written a function that’s little more than a wrapper around ConvertTo-HTML, for example, then your Pester tests aren’t going to be very complex, because you probably didn’t write much code. You’re not trying to make sure ConvertTo-HTML itself works because that’s not your code, so it’s not your problem in a unit test. Because so much of our PowerShell code is leveraging other people’s code, our own Pester tests are often simpler and easier to grasp.