Framework
pester/Pester avatar
pester/Pester

Pester: PowerShell testing, mocking and code coverage in one module

Pester is the ubiquitous test and mock framework for PowerShell.

3,349 stars477 forksPowerShellNOASSERTION

At a glance

What is it?
Pester is the test and mock framework for PowerShell. This article covers what it does, how to install it, how to write a first test, and where its documentation stops short.
Who is it for?
Adopt Pester if you write PowerShell that other people depend on, especially when it touches the filesystem, the registry or remote systems, because Mock and Should -Invoke let you assert on side effects without running them. Do not adopt it for a one-line script you will delete next week, or if you need a test framework whose documentation covers every parameter of every command: parts of the README point at pester.dev instead of explaining themselves.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 1 day ago.
What is it written in?
Mainly PowerShell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 1, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What Pester solves, and who ends up using it

PowerShell scripts start as one-liners and turn into deployment tooling. At that point the usual safety net is missing: there is no compiler, no type checker that catches a renamed parameter, and no test runner in the box on most systems. Pester fills that gap. It is a test framework written in PowerShell, for PowerShell, and it ships the three pieces you normally assemble separately: a runner that discovers and executes test files, an assertion vocabulary built around Should, and a mocking layer that replaces commands for the duration of a test.

The audience is narrower than the tagline suggests. Pester is for people who maintain .ps1 and .psm1 files that run repeatedly: build scripts, provisioning scripts, Azure and Active Directory automation, module code published to a gallery. If your PowerShell is throwaway glue typed once into a terminal, Pester adds a file, a naming convention and a runner invocation for no return. The README's own example makes the intended shape clear: you write a function, then you write a Describe block that calls it and asserts on the result.

Describe, It, Should and Mock: how a Pester run is structured

A Pester file is a script, not a declarative data file. That matters because it means test setup is ordinary PowerShell, with all the flexibility and all the footguns that implies. The README example wraps the function under test in a BeforeAll block, then nests a Describe, a Context and several It blocks. Describe and Context are grouping constructs that produce the indented output tree; It is the unit that passes or fails. Inside an It, the value under test flows into a Should assertion through the pipeline, so `$allPlanets.Count | Should -Be 8` reads as a sentence about the count.

Two mechanisms in that example are worth pulling out. The first is -TestCases, which takes an array of hashtables and runs the same It once per entry, binding the keys as parameters through a param block. That is how the README tests four name filters without writing four Its. The second is Mock. The mocking example defines Remove-Cache, replaces Remove-Item with an empty implementation via `Mock -CommandName Remove-Item -MockWith {}`, calls the function, and then asserts with `Should -Invoke -CommandName Remove-Item -Times 1 -Exactly`. The real deletion never happens; the assertion is about the call, not the file. That inversion, asserting on what was invoked rather than on what changed, is the part of Pester that changes how you design functions. Code that calls Remove-Item directly is testable only through this mechanism, so the mocking layer quietly pushes you toward functions that take their dependencies as commands rather than hiding them.

Installing Pester and running a first test file

Pester installs from the PowerShell Gallery as a module. The README notes that Pester 3 ships with Windows 10 but recommends updating, and gives this command, to be run as administrator:

powershell
Install-Module -Name Pester -Force

If you are not on Windows 10, or the install fails, the README sends you to the full installation and update guide at pester.dev rather than repeating the steps. One detail the README does state plainly: the signing certificate changed in 5.6.0, so updating across that boundary produces a certificate error, and you have to add -SkipPublisherCheck to get past it. The README also says Pester is now signed and that -SkipPublisherCheck should no longer be used for fresh installs from the Gallery on Windows 10. Those two statements are consistent but easy to misread, so check which situation you are in before copying a flag.

With the module installed, a test file is any .ps1 following the naming Pester discovers. The README's example is saved as Get-Planet.Tests.ps1 and run like this:

powershell
Invoke-Pester Get-Planet.Tests.ps1

The README also notes that pressing F5 in VS Code runs the same file, because the editor integration is part of the offering. What you should see is the Describe tree with each It marked passed or failed, plus a summary count. The README does not document the exit codes Invoke-Pester returns, which is the first thing you need when wiring this into a pipeline that should fail the build.

Where Pester gets in the way

The mocking model is the sharpest edge. Mock replaces a command by name within the scope of the test, and the README's example mocks a built-in cmdlet. That works, but it means a test can pass while the real command would have failed, and it means a mock that drifts from the real command's parameters will not be caught. There is nothing in the README about verifying that a mock still matches the command it stands in for.

Scope is the second issue. BeforeAll runs once for its Describe, and the README's example relies on that to define Get-Planet before the Its execute. Get the placement wrong and the function is undefined when the It runs, producing a failure that looks like a bug in the code under test. Pester 5 changed this discovery and run model, and the README does not explain the change; it points at pester.dev. Anyone upgrading a suite written for Pester 4 should expect to read the migration material rather than infer it.

Finally, Pester is the wrong tool when the thing you need to verify is not PowerShell. It runs your tests inside a PowerShell host, so testing a compiled .NET library, a container image or a web endpoint means driving those from PowerShell, and at that point a native test runner for the target platform is usually the better fit. Pester is also a poor choice when the test suite must run without a PowerShell installation, since there is no other way to execute it.

Pester against PSRule and plain assert scripts

The obvious alternative for a PowerShell shop is to skip a framework and write assertion scripts: a .ps1 that calls your functions and throws on mismatch, wired into CI. That approach has no dependency, no module version to pin, and no discovery convention to learn. It also has no test-case parameterisation, no structured pass and fail output, and no mocking, so any function that touches the real environment has to be tested against the real environment. Pester's value is concentrated exactly in those three gaps.

A different comparison is PSRule, which is aimed at validating infrastructure definitions and configuration files against rules rather than exercising your own functions. PSRule answers whether a YAML or Bicep file conforms; Pester answers whether your function returns eight planets when called with no arguments. They overlap only in that both produce pass and fail output in CI. If your problem is that a template drifted from policy, Pester's Describe and It vocabulary is the wrong shape for it, and you will spend more time building assertions than writing rules.

Maintenance, upgrades and the licence question

The repository is not archived, and the last push was on 2026-09-09, the same day as the 6.2.0 release. Two alpha builds preceded it in the same month, which is the normal shape for this project: alphas land, then a stable release. That cadence means upgrades arrive often enough that pinning a version in CI is worthwhile, and the certificate history in the README shows why. A module signed under a different authority will fail to import or update, and the README lists the thumbprint for each version range back to 2016 so you can identify what you have. The practical upgrade cost is that certificate transition plus the Pester 4 to 5 behavioural change, both of which are documented in the README or linked from it.

The LICENSE file sits at the repository root, but the metadata marks the licence as NOASSERTION, meaning the repository's own tooling could not classify it automatically. The README does not state a licence name. If you are vendoring Pester into a product or a locked-down build image, read LICENSE directly and have someone who can make that call review it; nothing in the README substitutes for that. The README does ask for sponsorship of the maintainers and the project through Open Collective and GitHub Sponsors, which is worth noting as a signal about how the work is funded.

Editorial conclusion

Adopt Pester if you write PowerShell that other people depend on, especially when it touches the filesystem, the registry or remote systems, because Mock and Should -Invoke let you assert on side effects without running them. Do not adopt it for a one-line script you will delete next week, or if you need a test framework whose documentation covers every parameter of every command: parts of the README point at pester.dev instead of explaining themselves. Before you commit, verify the certificate thumbprint your installed version actually reports, and confirm that your CI server can consume the NUnit XML output, since the README lists the integrations but does not walk through their configuration.

Frequently asked questions

What is Pester in PowerShell?

Pester is a test and mock framework for PowerShell. It provides a test runner, a set of Should assertions, and built-in mocking so you can replace commands with empty implementations during a test.

How do I install Pester in PowerShell?

Run Install-Module -Name Pester -Force as administrator. The README notes that Pester 3 comes pre-installed with Windows 10 but recommends updating, and points at the installation guide on pester.dev for other platforms.

How do I use Pester to test PowerShell code?

Write your function inside a BeforeAll block, then wrap assertions in Describe and It blocks, and run the file with Invoke-Pester. The README's Get-Planet example is saved as Get-Planet.Tests.ps1 and executed with Invoke-Pester Get-Planet.Tests.ps1, or by pressing F5 in VS Code.

What is Pester testing?

Pester testing means running PowerShell code through Pester's Describe, Context and It blocks so each assertion is reported as passed or failed. The README also describes code coverage measurement that can be exported to JaCoCo format for build servers.

Official sources

  1. Issues
  2. pester/Pester on GitHub
  3. Project website
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pester-pester.svg)](https://hysenlabs.com/projects/pester-pester)