Write Dynamic Unit Tests for your PowerShell Code with Pester

I wrote a blog article on: “PowerShell Script Module Design: Placing functions directly in the PSM1 file versus dot-sourcing separate PS1 files” earlier this year and I’ve moved all of my PowerShell script modules to that design and while today’s blog article isn’t part of a series, that previous one is recommended reading so you’re not lost when trying to understand what I’m attempting to accomplish.

Most unit tests that I’ve seen created with Pester for testing PowerShell code are very specific, the tests generally have hard coded values in them, and live in source control along with the code that they’re designed to test. What if I wanted to create unit tests for each of my modules to make sure they meet a certain standard? What if I could write them generically so the same or similar test wasn’t being written over and over again since creating redundant code sounds like a lot of technical debt and something I try to avoid when writing PowerShell code so why not apply the same principles when writing Pester tests?

As described in that previously referenced blog article, I’ve moved to separating all of my functions into separate PS1 files that are dot-sourced from a PSM1 script module file. All of the functions must be listed in the FunctionsToExport section of the module manifest file (or exported via Export-ModuleMember in the PSM1 file) otherwise module auto-loading won’t work properly. In my module design scenario, the base file name of each PS1 file matches the corresponding function name so I simply need to create a Pester test to compare the exported functions to the list of those base file names. Sounds simple enough, right?

I started by writing a Pester test, then wrapping it inside a function along with adding parameterization so it could be called just like any other function, accept dynamic input, and provide the same type of output that would normally be seen with any Pester unit test. This is some of the bonus content that I showed last week at the end of one of my presentations at the PowerShell and DevOps Global Summit 2016.

I’ll run this test on my MrToolkit module that’s part of my PowerShell repository on GitHub. The funny thing is this particular function is part of that module so in a way, it’s testing itself:


Based on the previous results, the first test tells me that 21 functions should have been exported but only 20 were so the test failed. Based on the failure of the second and fourth test and success of the third one, it’s easy to determine the problem is that more functions exist in the module directory than are specified in the manifest.

After updating the FunctionsToExport section in the module manifest file, the test completes successfully:


The Test-MrFunctionsToExport function can also be used to test multiple modules at the same time as in this scenario where I’ll test all of the modules in my GitHub repositories where the repository starts with the letter “A“. Notice that the Test-MrFunctionsToExport function accepts pipeline input:


Separating functions into PS1 files and dot-sourcing them from a PSM1 file definitely adds more complexity than placing them directly inside a module’s PSM1 file, but in my opinion the benefits outweigh the disadvantages.

I think of Pester tests as not only a form of beginning with the end in mind, but being intentional about determining if the desired end result is going to be produced by whatever tool I’m building with PowerShell.


1 Comment

  1. Johannes Prinz

    Like what you’ve done here. This can probably be take a little further. What you are after is like a almost editor/compile time checking for common issues like ReSharper in c# and linting tools in JavaScript. So adding your test cases to the likes of a PowerShell linting tool such as PSScriptAnalyzer would be great. This tool currently analyses all psm1 and ps1 files, be great to scope it to functions and module manifests as well.


Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: