Test your PowerShell code with Pester
Tags: powershell, testing, tutorial, devops
Published: 2021-10-11 20:55:43

---
title: Test your PowerShell code with Pester
published: true
description: In this article, we are looking at the test framework Pester, that's great for author and running tests on PowerShell code.
series: powershell-tutorials
tags: PowerShell, testing, tutorial, devops

cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z05dlvwed6mk3ftnzzhg.jpg
---

> TLDR; this article covers the testing framework Pester that you use to test your PowerShell scripts. 

## Why test

The reason you want to have tests are many:

- **Correctness**. Ensure your code works as as intended for certain scenarios.
- **Confidence**. When you have a lot of tests covering your code it creates a level of confidence. With this confidence you start daring to change this, if you for example would need to refactor code and ensure it still works after those changes.
- **Architecture**. Another reason for having tests is that it drives architecture. If you create tests around what you do, you ensure you build your code in a way that makes it testable. That, *drives the architecture*.

There are many other reasons for wanting to have tests but the three above are quite compelling.

## What is Pester

Pester is a test framework meant for PowerShell and is a module you can install. It has several features:

- **Assertions**. Pester comes with diverse ways of asserting conditions that will determine if your tests should fail or not.
- **Able to run tests**. You can run tests with Pester, both a single test with a single piece of input as well as testing many different inputs at once.
- **Can group your tests in test suites**. When you start having quite a few tests, you want a way to group those tests into larger logical groups, that's what test suites are.
- **Ability to mock calls**. In you tests you might have calls to commands that carry out side-effects, like accessing a data store or creating a file for example. When you want your tests to focus on the behavior on the tests, mocking is a good idea.

## Install

To install Pester, you run the below command.

```bash
Install-Module -Name Pester -Force
```

Once it's installed, you can start authoring your tests.

From install page:

> Pester runs on Windows, Linux, MacOS and anywhere else thanks to PowerShell. It is compatible with Windows PowerShell 3, 4, 5, 6 and 7.
> Pester 3 comes pre-installed with Windows 10

## Our first test

For our first test, we will learn how to write a test as well as running it.

1. To create our first test, create a file _A-Test.ps1_
2. Add the following code:

   ```powershell
   Describe "A suite" {
      It "my first test" {
        $Value = "Value"
        $Value | Should -Be "Value"
      }
    }
   ```

   The test above, have a `Describe` construct which is the declaration of a suite, and a string argument, giving the suite a name. Within the suite there's a test definition `It`, which also has a string argument that represents the name of the test. Within the test, there's test itself where the code is set up:

   ```powershell
   $Value = "Value"
   ```

   and then it's asserted upon:

   ```powershell
   $Value | Should -Be "Value"
   ```

   Note the use of the `Should -Be`, which determines equality between `$Value` and "Value".

3. To run the test, call `Invoke-Pester` (./ for the path in Linux ans macOS and .\ for Windows):

   ```powershell
   Invoke-Pester ./A-Test.ps1 
   ```

   The outcome of running the test is:

   ```output
   Starting discovery in 1 files.
   Discovery found 1 tests in 6ms.
   Running tests.
   [+] /<path>/A-Test.ps1 42ms (11ms|26ms)
   Tests completed in 44ms
   Tests Passed: 1, Failed: 0, Skipped: 0 NotRun: 0
   ```

## A more real looking test

The first test was great in that it let us understand the mechanics of testing and concepts like a suite, a test, and an assertion like `Should -Be`. A more real looking test would test code in a script file that's not in our test file. Here's the steps we will take next:

- Create a script file with our production code.
- *Dot source* said script file.
- Create a test and run it.

### Create production code

You will have code that you want to test but let's create this script file for the sake of demonstration.

1. Create a file _Get-Tomato.ps1_
2. Add the following code:

   ```powershell
   Function Get-Tomato() {
     new-object psobject -property @{ Name = "Tomato" }
   }
   ```

   This code will create a custom object for each time the `Get-Tomato()` function is invoked.

3. Let's _dot source_ it next so are session knows about it:

   ```powershell
   . ./Get-Tomato.ps1
   ```

4. Verify that your function has been picked up by running:

   ```powershell
   Get-Tomato
   ```

   you should see the following in the console:

   ```output
   Name                                                                                                                 ----                                                                                                                  
   Tomato
   ```

### Create the test

Now that we have our production code, let's author the test next.

1. Create a file _Get-Tomato.Tests.ps1_ and give it the following code:

   ```powershell
   Describe "Tomatoes" {
      It "Get Tomato" {
        $tomato = Get-Tomato
        $tomato.Name | Should -Be "Tomato"
      }
    }
   ```

2. Run the test with `Invoke-Pester`:

   ```powershell
   Invoke-Pester ./Get-Tomato.Tests.ps1
   ```

   you should see the following output:

   ```output
   Invoke-Pester ./Get-Tomato.Tests.ps1
   Starting discovery in 1 files.                                                                                                  Discovery found 1 tests in 6ms.                                                                                                 
   Running tests.
   [+] /<path>/Get-Tomato.Tests.ps1 66ms (9ms|52ms)
   Tests completed in 68ms
   Tests Passed: 1, Failed: 0, Skipped: 0 NotRun: 0
   ```

Great, you ran a test on a more real looking code. 

## Working with side effects

You will have code that you write that eventually performs side effects, like accessing a network resource or create a file. Let's look at such a case and how Pester handles it. The short answer is that you can use mocks, a construct that's executed instead of the actual command. All you need to do is to focus that the *right behavior* happens.

### Update production code

So, in this case, imagine that our production code now will have more function `Save-Tomato` that saves an object to a file.

1. Update the _Get-Tomato.ps1_file with this code:

   ```powershell
   Function Save-Tomato() {
      Param(
        [string] $Name
      )
      New-Item -ItemType File -Path ./Tomato.txt -Value $Name -Force
   }
   ```

2. _Dot source_ the code to ensure it's being picked up:

   ```powershell
   . /Get-Tomato.ps1
   ```

### Create a test

Ok, so you have added `Save-Tomato()` to your script file. Now for a test. Your code is calling `New-Item`, which creates a new file. As part of testing, you don't want it to create a file each time the test is being run. More likely, you just want to see the test does what it's supposed to, i.e. calling the correct command/s. So, to solve this issue, we can mock, replace the current implementation of `New-Item` with our own.

- To mock, we first need to replace the actual implementation like so:

    ```powershell
    Mock -CommandName New-Item -MockWith {}
    ```

- Call the command. At this point, you need to call the command like you would usually do. In your case, it means that you call `Save-Tomato()`:

   ```powershell
   Save-Tomato # this should call New-Item
   ```

- Verify. The last part of the mocking process is to verify that you mock has been called

1. The command `Should -Invoke`, allows you to specify what command it should have called, like so:

   ```powershell
   Should -Invoke -CommandName New-Item -Times 1 -Exactly
   ```

   The above code verifies `New-Item` is called exactly one time.

1. Let's put it all together as a test:

   ```powershell
   It "Save tomato" {
      Mock -CommandName New-Item -MockWith {}
      Save-Tomato "my tomato"
      Should -Invoke -CommandName New-Item -Times 1 -Exactly
   }
   ```

1. Remove _Tomato.txt_ and then run the test with `Invoke-Pester` like so:

   ```powershell
   Invoke-Pester ./Get-Tomato.Tests.ps1
   ```

   At this point your tests should run successfully like so:

   ```output
   Starting discovery in 1 files.
   Discovery found 2 tests in 8ms.
   Running tests.
   [+] /Users/chnoring/Documents/dev/projects/powershell-projects/articles/Get-Tomato.Tests.ps1 78ms (34ms|37ms)
   Tests completed in 80ms
   Tests Passed: 2, Failed: 0, Skipped: 0 NotRun: 0
   ```

   Also, note how _Tomato.txt_ isn't created, because you are mocking the call to `New-Item`, success.

Congrats, you've learned how to install test framework Pester, on top of that, you've learned to author your first tests and even learned how to mock the call to actual commands. To learn more, have a look at Pesters GitHub page:

> [Pester GH page](https://github.com/pester/Pester)