PowerShell How-To

How To Run Code Before and After a Pester Test

If you're writing PowerShell, you're also writing tests for that code, right? Let's just assume we live in a perfect world and everyone does for a moment. If not, I highly encourage you to check out Pester. Since you are writing tests for PowerShell scripts and modules, it's likely you've run into the problem of needing to do some kind of "setup" and "teardown" tasks before and after your tests run. Rather than just throw some code in before your test and after, Pester provides a native ability to invoke this code.

Why would running code before and after each test even be a necessity anyway? Because there are times when in order to perform a specific test, the state of the test must be in a specific state or something invoked inside of the test itself must be at some predefined point. For example, when testing code that uses PowerShell remoting, it's common to need a PS remoting session active before the test is run to test with. Likewise, it's not good practice to leave it around after the test ends so it needs to be cleaned up. Regardless of the case, Pester allows this behavior.

There are two ways that Pester allows invoking code before and after tests. Pester can execute code before and after each test or before and after every test. The code to do so is similar but will behave much differently.

Let's start with an example. Perhaps I've got a single describe block that contains two tests (it blocks) for a function called Do-ThingToServer. This function has a parameter called Session that represents a connected PowerShell remoting session. Once passed, the Do-ThingToServer function invokes some kind of code on the server.

The function and tests looks like below:

function Do-ThingToServer  {
param(
$Session
)
Invoke-Command -Session $Session -ScriptBlock { 'hello' }
}

describe 'Do-Thing' {
it 'does that thing when the session for FOO is passed to it' {
Do-ThingToServer -Session $Session
}

    'it does not do that thing when the session for FOO is passed to it' {
Do-ThingToServer -Session $Session
}
}

When creating unit tests for this function, it's important not to actually attempt to open a PowerShell remoting session for this computer. Instead, we need to create a "fake" session to pass to the function. Inside of each it block where does the $Session variable come from? It can come from using Pester's BeforeEach and AfterEach constructs. Perhaps I'd like to create a new session before each test runs. My test would then turn into something that looks like this:

describe 'Do-Thing' {

    BeforeEach {
$script:session = New-PSSession -ComputerName localhost
}

    AfterEach {
$script:session | Remove-PSSession
}

    it 'does that thing when the session for FOO is passed to it' {
Do-ThingToServer -Session $script:Session
}

    'it does not do that thing when the session for FOO is passed to it' {
Do-ThingToServer -Session $script:Session
}
}

Notice in this case, since I'm using the result of New-PSSession in my tests, I need to set the scope to script so that the tests can see that variable. This is unrelated to the actual functionality of BeforeEach and AfterEach.

In the configuration, above, a new session will be created before each it block is invoked and it will be removed afterwards. Similarly, since I'm not actually changing the session between tests I could choose to just create a new session once and then tear it down once. This would prevent one extra session from being created. To ensure code is executed before and after all tests are complete we can use the BeforeAll and AfterAll constructs.

BeforeAll {
$script:session = New-PSSession -ComputerName localhost
}

AfterAll {
$script:session | Remove-PSSession
}

Now we can be sure that only a single remoting session would be created right before the first test and immediately after the last test.

Next time, rather than inserting code directly into the describe block, consider using each of the constructs we've went over today. You'll find that it makes executing code before and after your tests much easier to maintain.

About the Author

Adam Bertram is an independent consultant, technical writer, trainer and presenter. Adam specializes in consulting and evangelizing all things IT automation mainly focused around Windows PowerShell. Adam is a Microsoft Windows PowerShell MVP, 2015 powershell.org PowerShell hero and has numerous Microsoft IT pro certifications. He is a writer, trainer and presenter and authors IT pro course content for Pluralsight. He is also a regular contributor to numerous print and online publications and presents at various user groups and conferences. You can find Adam at adamtheautomator.com or on Twitter at @adbertram.

comments powered by Disqus

SharePoint Watch

Sign up for our newsletter.

I agree to this site's Privacy Policy.