Getting Started with Pester

Summary: Guest blogger, Dave Wyatt explains how to get information back from Pester.

   Note   This is a five-part series that includes the following posts:

At the end of yesterday’s post, I showed this brief example of a .Tests.ps1 file:

Image of command output

Today, we’ll go into more detail about what goes into these tests, and how to get information back from Pester.

In the example screenshot, there are four new commands that are not part of the PowerShell language: Describe, Context, It, and Should.

Defines a group of tests, and all Pester tests files must contain at least one Describe block. For the most part, all other Pester commands must be placed inside a Describe, or they will produce an error.

Defines an optional subgroup of tests inside a Describe. This can be used to scope certain variables and state in such a way that the Describe is not modified past the end of the Context block. I’ll go into more detail about how this affects other Pester features later.

Defines a single test case. When you run Invoke-Pester, each It block will produce a pass/fail status.

Describe, Context, and It are alike in that they are assigned a name, and a script block containing the code that they execute. These are fully functional PowerShell script blocks that can contain whatever code your tests require, and they follow the usual rules of variable scoping for PowerShell script blocks. This means that if you assign a variable inside of an It block, it will not be present in the parent Context or Describe block.

On the other hand, the Should command is used to define assertions in Pester. Assertions are simple statements that must be True for the test to pass. Pester was originally inspired by a Ruby test framework called RSpec, which uses some of the same command names. It was intended to be a Behavior-Driven Development framework, which simply means that the tests are more human-readable. For example, the following lines of code read like a plain sentence:

“$true | Should Be $true” would pass, and “$true | Should Be $false” would fail

To produce that plain language structure, the Should command takes pipeline input and defines a series of operators, such as Be and BeExactly, which you can see in the example screenshot. These operators are described in more detail in the about_Should Help file, but here are some of the more commonly used operators:

  • Should Be: The items must be equal. When comparing strings, the comparison is not case sensitive.
  • Should BeExactly: The items must be equal. When comparing strings, the comparison is case sensitive.
  • Should Throw: The item on the left must be a ScriptBlock object. When it is executed, it must throw a terminating error for the test to pass. You may optionally include a partial message to the Should Throw command. If so, the error that was thrown must contain the specified message for the test to pass.

You may optionally include the word Not before the operator, to negate the effect. For example:

“$true | Should Not Be $false” would pass, and “$true | Should Not Be $true” would fail

It is a matter of personal preference whether you place multiple calls to the Should command within a single It block, or use a separate It block for each assertion. The difference is that the It block will stop executing as soon as a single assertion has failed.

When an assertion fails, Pester gives you quite a bit of information about the failed assertion, including the line of code that contains the Should command, and the expected and actual values (where applicable), for example:

Image of command output

The Describe, It, and Should commands will be present in any Pester test suite, and in some cases, they may be all you need to write the whole suite.

Now, let’s have a closer look at the Invoke-Pester cmdlet. In the previous example screenshots, I’ve run it with no parameters, and allowed the output to go to the console. This is good for interactive use while I’m writing code, but when it comes time to plug Pester into a continuous delivery pipeline, we’ll want something more structured. Pester contains several options for getting information about its test results:

  • The –OutputFile and –OutputFormat parameters.
    These allow you to have Pester write its status to a file at the end of the test run. Currently, the only supported format is the NUnit XML standard, but others could be added. Because NUnit is so widely used, pretty much any continuous integration tool should be able to read the file and give you detailed information via its GUI or API.
  • The –PassThru switch.
    Normally, Invoke-Pester doesn’t produce any pipeline output, but by using –PassThru, you can assign the results to a variable. This output will be a single PSObject that contains several properties, such as FailedCount, PassedCount, and TestResult. (Test-Result is an array that contains an object with information about each It block that was executed.) This is useful for build servers, which allow you to run arbitrary PowerShell code, but may not necessarily have support for reading NUnit XML files. (You can also use the two options together.)
  • The –EnableExit switch.
    This will cause Pester to exit the PowerShell process when it finishes running. The exit code will be the number of failed tests, which causes Pester to behave as command-line executables are generally expected to behave: an exit code of zero is a good thing, and anything else is bad. This can be used with build servers that don’t support NUnit XML, and only support running traditional command-line tools instead of PowerShell code. (These should be pretty rare now; everyone seems to recognize the value of PowerShell.)

I think that’s enough new information for one day. Tomorrow, we’ll dive into Pester’s mocking framework, which can enable you to write unit tests for your PowerShell code.


Thanks, Dave!

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy

Comments (1)

  1. Brian Benson says:

    Good stuff Dave. Very helpful info.

Skip to main content