{"id":80418,"date":"2018-08-16T16:32:49","date_gmt":"2018-08-16T16:32:49","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=80418"},"modified":"2025-12-17T14:05:23","modified_gmt":"2025-12-17T14:05:23","slug":"introduction-to-testing-your-powershell-code-with-pester","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/introduction-to-testing-your-powershell-code-with-pester\/","title":{"rendered":"Introduction to Testing Your PowerShell Code with Pester"},"content":{"rendered":"<p><strong>The series so far:<\/strong><\/p>\n<ol>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/introduction-to-testing-your-powershell-code-with-pester\/\">Introduction to Testing Your PowerShell Code with Pester<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/advanced-testing-of-your-powershell-code-with-pester\/\">Advanced Testing of Your PowerShell Code with Pester<\/a><\/li>\n<li><a href=\"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/testing-powershell-modules-with-pester\/\">Testing PowerShell Modules with Pester<\/a><\/li>\n<\/ol>\n\n\n\n\n<p>Automation has become the backbone of infrastructure management within most corporations. The DevOps movement has added to the importance of having a good automation strategy. With its usefulness on the Windows platform long established, and now the ability to run on the Linux and Apple Mac OSX platforms, PowerShell has firmly established itself as a powerful player in the world of automation.<\/p>\n\n\n\n<p>Given the importance of PowerShell, imagine that your boss, project manager, or similar authority figure comes to you with some basic questions.<\/p>\n\n\n\n<p><em>\u201cHow can I be confident your code meets requirements?\u201d<\/em><\/p>\n\n\n\n<p><em>\u201cHow do we know your changes don\u2019t break other modules?\u201d<\/em><\/p>\n\n\n\n<p><em>\u201cCan you prove to me your scripts do everything they are supposed to?\u201d<\/em><\/p>\n\n\n\n<p>These and other questions can be answered through the use of testing.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-pester\">Pester<\/h2>\n\n\n\n<p>\u201cSure\u201d you say. \u201cI test my code.\u201d But in a shockingly high number of environments testing is still a manual process. A developer makes changes, runs a test on their computer, and deploys. Unfortunately, this type of testing just doesn\u2019t scale. A developer may be able to test the small script they created, or the function they updated. But what about bigger code bases? Modules composed of multiple PS1 files, or scripts that rely on many different modules?<\/p>\n\n\n\n<p>Just as automation is the answer to infrastructure management, so too is it the answer to testing. From the title of this article, you\u2019ve guessed by now the tool of choice for testing PowerShell code is Pester.<\/p>\n\n\n\n<p>Pester is a community-based project designed from the ground up as a testing framework for PowerShell, written in PowerShell. It\u2019s open source, you can look through the source code, even make contributions back to it. You\u2019ll find the full <a href=\"https:\/\/github.com\/pester\/Pester\">project<\/a> on GitHub.<\/p>\n\n\n\n<p>A lot of effort went into making Pester as compatible as possible across multiple versions and platforms. It is compatible with PowerShell 2.x up through 5.x on Windows 10, 8, 7, Vista, and all versions of Windows Server from 2003 through today. It is even compatible with the new PowerShell 6.0 Core, running on Linux\/Mac OSX platforms, with a few minor limitations. (See the article <a href=\"https:\/\/github.com\/pester\/Pester\/wiki\/Pester-on-PSCore-limitations\">Pester on PSCore limitations<\/a> for more information).<\/p>\n\n\n\n<p>In this series of articles, I\u2019ll introduce Pester and show examples of the different types of tests you can perform.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-types-of-testing\">Types of Testing<\/h2>\n\n\n\n<p>Before getting into writing tests, I will cover the types of testing. These break into three basic categories. While there are entire books written around testing concepts, this will be as brief as possible to provide context to basic testing operations.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-unit-testing\">Unit Testing<\/h3>\n\n\n\n<p>Unit tests are performed by the developer and are typically focused on the code they\u2019ve just created or modified. They provide feedback that the code works as they wanted it to. Unit tests are done in <em>isolation<\/em>. By isolating the test to run on just the code they\u2019ve written, and not that of external modules, they can be assured any problems they find are with their code and not with external modules or functions.<\/p>\n\n\n\n<p>To achieve isolation, testing uses the concept of <em>mocks<\/em>. Within a test a mock is used instead calling the actual external function desired. For example, let\u2019s say your script calls <strong>Test-Path<\/strong> to validate the existence of a file. Actually, calling the real <strong>Test-Path<\/strong> function could cause several issues in testing.<\/p>\n\n\n\n<p>First, the <strong>Test-Path<\/strong> cmdlet itself could have a bug in it, previously undiscovered or maybe just not known to the developer. Second, the developer could be assuming the path containing the file they are seeking will always exist as part of the test. Issues would certainly arise if the directory was to unexpectedly vanish. Finally, the drive containing the file may not be present or issues such as network connectivity or hardware failure could be causing problems.<\/p>\n\n\n\n<p>Should any of these issues occur, the developer is left not only trying to debug his own code, but also struggling with the many ways the <strong>Test-Path<\/strong> cmdlet could have failed.<\/p>\n\n\n\n<p>Mocks provide a way to remove external code, such as <strong>Test-Path<\/strong>, from the equation. As you will see later in this series, you can create a \u2018fake\u2019 or \u2018mock\u2019 version of <strong>Test-Path<\/strong> that would always return a true (or false). This removes the external call (in this case to <strong>Test-Path<\/strong>) as a possible vector for errors a developer might have to track down. The next article in the series will dive deeper into mocks.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-integration-testing\">Integration Testing<\/h3>\n\n\n\n<p>Integration testing is the next step in your testing workflow. Once a developer successfully completes their unit tests, they are ready for integration testing. Integration tests go beyond just testing the code the developer has finished working on, to testing it along with all the related code for a project.<\/p>\n\n\n\n<p>For example, let\u2019s say you updated two functions in module A. This module is part of a bigger project that encompasses two other modules, B and C, in addition to A. When executing integration tests, it would call all of the tests for all three modules. This is to ensure changes to module A don\u2019t adversely affect modules B and C.<\/p>\n\n\n\n<p>Typically, integration tests do not employ mocks. To fully test integration, in addition to your own code, you should execute that code against other modules. These modules might include some you\u2019ve purchased, or those provided by Microsoft such as <strong>AzureRM<\/strong> or <strong>SqlServer<\/strong>. Integration testing is often considered \u2018<em>white box\u2019<\/em> testing. In white box testing, also referred to as clear box or glass box, the tester has access to the underlying source code.<\/p>\n\n\n\n<p>Many source code control systems have the ability to automatically perform integration testing. Once code is checked in, the system will automatically execute the integration tests you\u2019ve configured.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-acceptance-testing\">Acceptance Testing<\/h3>\n\n\n\n<p>Acceptance tests should be done by someone other than the developer. Some companies have internal organizations set up just to perform testing. In other organizations business users are often employed as testers, although this isn\u2019t as common when testing non-application projects such as PowerShell scripts.<\/p>\n\n\n\n<p>Acceptance testing is typically done in a \u2018<em>black box\u2019<\/em> style. In black box testing, the testers do not look at or have access to the source code. Instead they simply execute the scripts and look at the results. If the results are as expected, for example a new server is created or database is deployed, the test passes.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-when-to-test\">When to Test<\/h2>\n\n\n\n<p>Let\u2019s say by the end of this series of articles, you\u2019re sold on testing your PowerShell code with Pester. You\u2019ll want to start by crafting tests for the modules and scripts that you already have. Typically, these tests are written against what you expect the code to do. While you might think your tests would all just pass every time, you\u2019d be surprised at how often you uncover bugs in your existing code when creating tests. Additionally, the creation of these tests will give you a base for testing new updates to your scripts.<\/p>\n\n\n\n<p>The second time to test is before you write your scripts. Yes, you read that right, you should create your tests <em>before<\/em> you write your new scripts (or update existing ones with new functionality). The concept is known as <em>test driven development<\/em>, or TDD for short.<\/p>\n\n\n\n<p>With test driven development, you begin with your requirements document. You then create a test for each requirement. In addition, you\u2019ll also want to ensure you create tests for failures. For example, say your requirement is to download a file from a website via FTP every day. Naturally you\u2019ll have a test for successful downloads, but you should also have tests for when the download fails to ensure your code behaves according to the requirements for error handling.<\/p>\n\n\n\n<p>TDD also helps us to answer the question of \u201care we done\u201d. If you have tests for each requirement when all of your tests pass, you\u2019ve met all of your requirements, and thus development is complete.<\/p>\n\n\n\n<p>As should be obvious, in order to properly do test driven development you must have good, clear, and documented requirements. I cannot stress how important this is. In far too many development shops, requirements are provided with a few scribbles on the back of a napkin, or even worse, verbally.<\/p>\n\n\n\n<p>Your automation strategy is a critical component in your corporation\u2019s infrastructure. Even a small script with just a few lines of code can have an enormous impact in your company. Imagine a simple script meant to remove a single resource group from Azure. Improperly configured, it could wind up deleting ALL of the resource groups, including those in your production environment!<\/p>\n\n\n\n<p>Demand clear, well written requirements. If you cannot get them, then write them yourself! Base them on your understanding of the user\u2019s needs. Once done, send them to the user, letting them know development will proceed once they provide formal approval via email.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-the-demos\">The Demos<\/h2>\n\n\n\n<p>The demo code for this series of articles was written on Windows 10, 64-bit, using PowerShell 5.1. The code was developed in the PowerShell ISE.<\/p>\n\n\n\n<p>For all of my PowerShell articles, a root folder on the C drive was created, <em>C:\\PowerShell<\/em>. For this article, a new folder <em>Pester-Demo<\/em> was generated, hence <em>C:\\PowerShell\\Pester-Demo<\/em> is where all the code is being executed from. However, you are not locked into this structure. To make it easy at or near the beginning of each script is a variable, <strong>$dir<\/strong>, which points to the demo folder. Just update this to point to the folder you want to place the demos in.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$dir = 'C:\\PowerShell\\Pester-Demo' <\/pre>\n\n\n\n<p>In addition, the final set of demo scripts for can be found on the author\u2019s <a href=\"https:\/\/github.com\/arcanecode\/PowerShell\/tree\/master\/PesterBasics\">GitHub repository<\/a> for this article.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-installing-updating-pester\">Installing \/ Updating Pester<\/h2>\n\n\n\n<p>Installation of Pester is pretty simple if you are using PowerShell version 5.x (5.0 or 5.1). As version 5 is the most widely used version today, I\u2019ll cover installing using it below. If you are still on an older version of PowerShell the Pester site on GitHub has clear <a href=\"https:\/\/github.com\/pester\/Pester\/wiki\/Installation-and-Update\">instructions<\/a>.<\/p>\n\n\n\n<p>Assuming you are on PowerShell version 5.x, you can find out what version of Pester is currently available by using the <strong>Find-Package<\/strong> cmdlet.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Find-Package Pester<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"399\" height=\"63\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-54.png\" alt=\"\" class=\"wp-image-80419\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>As you can see, as of this writing, 4.4.0 is the most recent version as of the date of this article. To install it, simply use the Install-Module cmdlet, but be sure you are running the ISE or PowerShell console in Administrator mode or the install will fail.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Install-Module Pester -Force -SkipPublisherCheck<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>If you\u2019ve previously used <strong>Install-Module<\/strong>, the switches may not be ones you\u2019ve used before. <strong>Force<\/strong> will do the install even if you have Pester installed. The <strong>SkipPublisherCheck<\/strong> argument is important if you are running on Windows 10. As mentioned before, Pester was pre-installed on Windows 10. However, the code was installed using a code signing certificate that is different from the one used today on the GitHub \/ PSGallery version. Because the certificates don\u2019t match, PowerShell will raise an error and not allow you to proceed. Normally this would be a good thing, as it would prevent evil hackers from trying to overwrite a module you trust with one of theirs. In this case, though, you are cognizant of what you are doing and are requesting the update. Hence, you need the <strong>SkipPublisherCheck<\/strong> as a way to tell PowerShell you know the certificates don\u2019t match, go ahead and install.<\/p>\n\n\n\n<p>You can include both switches without any issues even if you aren\u2019t on Windows 10 and don\u2019t currently have Pester installed. To validate the version that was installed, you can use <strong>Get-Module<\/strong>.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Get-Module Pester -ListAvailable<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"227\" height=\"104\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-55.png\" alt=\"\" class=\"wp-image-80420\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>On this system there are three versions. Version 3.4.0 was preinstalled with Windows 10. When I first started writing this article, 4.3.1 was the current version, and was installed using the <strong>Install-Module<\/strong> cmdlet above. Shortly afterward version 4.4.0 was released, so the following cmdlet was used to update Pester to the most current version.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Update-Module Pester -Force<\/pre>\n\n\n\n<p>If you only have 3.x installed, you will need to use the <strong>Install-Module<\/strong> method, after you have version 4.0 or later installed from the gallery, you will be able to use <strong>Update-Module<\/strong> to keep it up to date.<\/p>\n\n\n\n<p>You\u2019ll find the code from this section in the file <em>Get-Pester.ps1<\/em> in the author\u2019s <a href=\"https:\/\/github.com\/arcanecode\/PowerShell\/tree\/master\/PesterBasics\">GitHub repository<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-running-tests\">Running Tests<\/h2>\n\n\n\n<p>Before you start writing tests, you should know how to run them. The Pester module includes the <strong>Invoke-Pester<\/strong> function. With it, you provide either the name of a script containing the tests to execute, or the name of a folder. By convention, although not required, scripts with Pester tests should end with <em>.Tests.ps1<\/em>. While not a requirement, you will typically create a tests file for each <em>ps1<\/em> file you have. If you had a file, <em>DoSomeStuff.ps1<\/em>, its corresponding test file would be <em>DoSomeStuff.Tests.ps1<\/em>. This convention allows you to execute all tests in a folder by using <em>Invoke-Pester<\/em> and passing in the name of a directory. It will find and run all files that have the <em>.Tests.ps1 <\/em>extension.<\/p>\n\n\n\n<p><a id=\"post-80418-_Hlk522118983\"><\/a> For this article, all the tests will be stored in the file <em>BasicPester.Tests.ps1<\/em>. You\u2019ll use <strong>Invoke-Pester<\/strong> to run this tests file. Store the code below in the script, <em>Invoke-BasicPesterTests.ps1<\/em>, or you can download the file from the <a href=\"https:\/\/github.com\/arcanecode\/PowerShell\/tree\/master\/PesterBasics\">GitHub repository<\/a> for this article.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$dir = 'C:\\PowerShell\\Pester-Demo'\nInvoke-Pester \"$dir\\BasicPester.Tests.ps1\"<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>Alternatively, you could have used <strong>Invoke-Pester $dir<\/strong>, and it would have run all files ending in <em>.Tests.ps1<\/em>, including <em>BasicPester.Tests.ps1<\/em>. Finally, you could have also just run <em>Invoke-Pester<\/em>, in which case it would execute all <em>*.Tests.ps1<\/em> files in the current folder. If your PowerShell session was currently in <em>C:\\PowerShell\\Pester-Demo<\/em>, Invoke-Pester will run all <em>.Tests.ps1<\/em> files in that folder.<\/p>\n\n\n\n<p>Now that you know how to run tests, it\u2019s time to start writing them!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-your-first-test\">Your First Test<\/h2>\n\n\n\n<p>Take a look at a very simple test.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Describe 'Basic Pester Tests' {\n  It 'A test that should be true' {\n    $true | Should -Be $true\n  }\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>Under the hood, Pester commands are really nothing more than PowerShell functions. Thus, the <strong>Describe<\/strong> method (aka function) is the initial method called. One thing you\u2019ll notice about Pester, is that it does not follow the naming conventions of other PowerShell cmdlets. Most, even when you author your own functions, use the verb-noun naming convention.<\/p>\n\n\n\n<p>The authors of Pester chose to go a different route. Pester uses a language of its own, one meant to make tests more readable. This concept is known as a DSL, or <em>Domain Specific Language<\/em>. With DSLs, a syntax is created that is much more readable and friendlier to the human users. You will find Pester implemented a DSL that is meant to make tests easily read and convey a clear meaning as to what is going on.<\/p>\n\n\n\n<p>As noted, a basic Pester test begins with the <strong>Describe<\/strong> command. The <strong>Describe<\/strong> function acts as a container for one or more tests. After <strong>Describe<\/strong>, a text string that describes the tests contained in it. This example has a simple name of <strong>Basic Pester Tests<\/strong>. Under the hood, this string is the first parameter to the <strong>Describe<\/strong> function in the Pester module.<\/p>\n\n\n\n<p>At the end of the line there is a <strong>{<\/strong> (an opening squiggly brace). The next line has more code, which continues until you find the closing <strong>}<\/strong> (squiggly brace). At first glance this structure resembles other built-in PowerShell commands, such as <strong>foreach<\/strong>. This is a bit deceptive, though. What is really happening is that you are defining a <em>script block<\/em> and passing it into the Pester modules <strong>Describe<\/strong> function. A script block is PowerShell code that has been defined as an object. The previous code could have been defined like:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">$scriptBlock = {\n  It 'A test that should be true' {\n    $true | Should -Be $true\n  }\n}\nDescribe 'Basic Pester Tests' $scriptBlock<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>It would work, however, this makes the code more difficult to read and thus should be avoided, at least for your Pester tests. For more information on script blocks, see the <a href=\"https:\/\/docs.microsoft.com\/en-us\/powershell\/module\/microsoft.powershell.core\/about\/about_script_blocks?view=powershell-5.1\">About Script Bocks<\/a> article.<\/p>\n\n\n\n<p>This does have one other implication you should be conscious of. With a <strong>foreach<\/strong> block, you have the freedom to place the opening squiggly brace on the same line as the <strong>foreach<\/strong>, or on the next line. Both of these are valid:<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">foreach ($x in $list) {\n  # code here\n}\nforeach ($x in $list) \n{\n  # code here\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>This isn\u2019t allowed with Pester tests, as the script block is a parameter to the <strong>Describe<\/strong> function. If the brace was on the next line, PowerShell would not be able to find it and return an error for a missing parameter (the script block). If you really wanted to, you could place a line continuation character at the end, then the opening squiggly brace on the next line. However, this doesn\u2019t aid anything in terms of readability.<\/p>\n\n\n\n<p>So now you\u2019ve seen how to call the <strong>Describe<\/strong> function, given it a name, and then created a script block to hold one or more tests. A test is defined using the Pester function <strong>It<\/strong>. Like the structure of the <strong>Describe<\/strong> function, you first pass in a string containing the name of the test. This is followed by a script block that defines the test condition. Save the code from the beginning of this section to your <em>BasicPester.Tests.ps1<\/em> file in the folder you created.<\/p>\n\n\n\n<p>For this type of test, you first execute some type of equation, comparison, or function call that results in a Boolean value. This example is simply using the Boolean value of <strong>$true<\/strong>.<\/p>\n\n\n\n<p>The results of that equation are then piped to the Pester <strong>Should<\/strong> function. The first thing to supply to the <strong>Should<\/strong> function is a switch that indicates the expected results. The <strong>-Be<\/strong> switch indicates that what is being piped into <strong>Should<\/strong> needs to equal the value passed as the second parameter. This example is saying the constant <strong>$true<\/strong> must equal the <strong>$true<\/strong> being passed into the <strong>Should <\/strong>function\u2019s second parameter.<\/p>\n\n\n\n<p><a id=\"post-80418-_Hlk522119004\"><\/a><a id=\"post-80418-_Hlk522120046\"><\/a> Execute the test and look at the results. With the <strong>Describe<\/strong> example at the top of this section saved in a file <em>BasicPeter.Tests.ps1<\/em>, execute the <em>Invoke-BasicPesterTests.ps1<\/em> file (shown in the earlier section Running Tests).<\/p>\n\n\n\n<p>You should see the following output (your output colors may vary depending on your color settings in the ISE or PowerShell console).<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"663\" height=\"187\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-56.png\" alt=\"\" class=\"wp-image-80421\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>The first line reports that it is executing all tests in the PS1 file. If you had just called <strong>Invoke-Pester<\/strong> without providing a specific file, this would just display the name of the folder passed in (or the current folder if no folder was passed in). The next line, <em>Executing script\u2026<\/em> tells which <em>.Tests.ps1<\/em> file is getting executed for this section of output. This is useful when you are executing multiple test files at the same time.<\/p>\n\n\n\n<p>Next, you\u2019ll see the first (and only for this test) <strong>Describe<\/strong> block being executed. The Basic Pester Tests echoes back the string supplied as the first parameter to the <strong>Describe<\/strong> function.<\/p>\n\n\n\n<p>After the first parameter string, you\u2019ll see a <em>+<\/em> followed by the name of the test, the string supplied to the <strong>It<\/strong> function. The <em>+<\/em> is the indicator that the test passed successfully! Following is the length of time the test took, 36ms for this example.<\/p>\n\n\n\n<p>On the next line is the total run time for all tests, since it only had one test it took 36ms. The last line is a summary, it tells us how many tests passed, failed, were skipped, pending, or inconclusive. Passed and failed are pretty obvious. In a later article you\u2019ll see how to flag tests to be skipped, or put into pending status, as well as what inconclusive results are.<\/p>\n\n\n\n<section id=\"my-first-block-block_030fe7ecad8a6f389854f466b514b567\" class=\"my-first-block alignwide\">\n    <div class=\"bg-brand-600 text-base-white py-5xl px-4xl rounded-sm bg-gradient-to-r from-brand-600 to-brand-500 red\">\n        <div class=\"gap-4xl items-start md:items-center flex flex-col md:flex-row justify-between\">\n            <div class=\"flex-1 col-span-10 lg:col-span-7\">\n                <h3 class=\"mt-0 font-display mb-2 text-display-sm\">Automate your SQL workflows with PowerShell and Redgate<\/h3>\n                <div class=\"child:last-of-type:mb-0\">\n                                            With tools like Redgate Monitor, SQL Clone, SQL Change Automation, SQL Data Catalog, and Redgate Flyway, you can monitor servers, create clones, deploy database changes, and more \u2013 all from your PowerShell scripts.                                    <\/div>\n            <\/div>\n                                            <a href=\"https:\/\/www.red-gate.com\/products\/\" class=\"btn btn--secondary btn--lg\" aria-label=\"Explore the full portfolio: Automate your SQL workflows with PowerShell and Redgate\">Explore the full portfolio<\/a>\n                    <\/div>\n    <\/div>\n<\/section>\n\n\n<h2 class=\"wp-block-heading\" id=\"h-your-second-test-failure-is-an-option-after-all\">Your Second Test \u2013 Failure Is an Option After All!<\/h2>\n\n\n\n<p>What does it look like when your test fails? Modify the original code to add a second test.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Describe 'Basic Pester Tests' {\n  It 'A test that should be true' {\n    $true | Should -Be $true\n  }\n  It 'A test that should fail' {\n    $fail | Should -Be $true\n  }\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>The second test in a <strong>Describe<\/strong> script block is <strong>A test that should fail<\/strong>. Passing in the Boolean fail to the <strong>Should<\/strong> function and comparing that to true will of course cause this test to fail. When you run the tests, you\u2019ll see this for our output:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"738\" height=\"273\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-57.png\" alt=\"\" class=\"wp-image-80422\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>The second test appears with a <strong>\u2013<\/strong> sign, and all in red! This is the indication that the test failed in 13ms. The next line displays the expected result (the result after the <strong>Should -Be<\/strong>) and what was actually passed in. A line number and the code that trigged the failure are provided. On the last line of the results for this test, you\u2019ll see the full file name with the test.<\/p>\n\n\n\n<p>After this is the total time for all of the tests, then a summary indicating the number that passed, failed, etc. As you can see, the failures are displayed in red letters.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-more-should-than-should-be-allowed\">More Should than Should Be Allowed<\/h2>\n\n\n\n<p>There are actually many variations to the <strong>Should<\/strong> function. Another popular one is the <strong>-Exist<\/strong> switch. It takes a file name that is piped in and checks to see if it exists.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Describe 'should exist test' {\n  It 'Should exist' {\n    'C:\\PowerShell\\Pester-Demo\\Invoke-BasicPesterTests.ps1' |\n      Should -Exist\n  }\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>This can be very useful, especially when testing functions that download or create files. It can also be useful for validating your code. For example, you are writing a module. One of your tests might be to check the existence of your manifest file. The output from the test above looks like:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"657\" height=\"185\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-58.png\" alt=\"\" class=\"wp-image-80423\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Nice, but remember this is PowerShell! You can actually use PowerShell code as part of the tests. Take a look at this version of the test.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Describe 'should exist with variables test' {\n    $someFile = 'C:\\PowerShell\\Pester-Demo\\Invoke-BasicPesterTests.ps1'\n    It \"$someFile should exist\" {\n      $someFile | Should Exist\n    }\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>Here the file being tested for is placed in a variable. This lets you use string interpolation to make the file name part of the name you give to the test. And you can reuse the variable passing it into the <strong>Should<\/strong>.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"741\" height=\"180\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-59.png\" alt=\"\" class=\"wp-image-80424\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>Now the file name is part of the test name itself. You will know exactly what file name was being tested for, making the results more valuable, especially when you may have a situation with multiple files.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-providing-context\">Providing Context<\/h2>\n\n\n\n<p>Often a <strong>Describe<\/strong> block can contain many tests. When there are quite a few, it can be helpful to group related tests into blocks. This is where the <strong>Context<\/strong> function comes into play. You can think of a <strong>Context<\/strong> as a sub-<strong>Describe<\/strong>, it will provide an extra level in the output. In the following code sample, the tests are grouped into Context groups. In addition, you\u2019ll also see some other variations of <strong>Should<\/strong>. Finally, for a few of the tests, you\u2019ll condense the script blocks being passed into the <strong>It<\/strong> functions onto a single line. Just to demonstrate, it isn\u2019t always necessary to break them up across multiple lines.<\/p>\n\n\n\n<pre class=\"wp-block-preformatted\">Describe 'Grouping using Context' {\n    Context 'Test Group 1 Boolean Tests' {    \n      It 'Should be true' { $true | Should -Be $true }\n      It 'Should be true' { $true | Should -BeTrue }\n      It 'Should be false' { $false | Should -Be $false }      \n      It 'Should be false' { $false | Should -BeFalse }      \n    }\n    Context 'Test Group 2 - Negative Assertions' {    \n      It 'Should not be true' { $false | Should -Not -BeTrue }\n      It 'Should be false' { $true | Should -Not -Be $false }\n    }\n    Context 'Test Group 3 - Calculations' {    \n      It '$x Should be 42' {\n        $x = 42 * 1 \n        $x | Should -Be 42\n      }\n      \n      It 'Should be greater than or equal to 33' {\n        $y = 3 * 11\n        $y | Should -BeGreaterOrEqual 33\n      }      \n      It 'Should with a calculated value' {\n        $y = 3\n        ($y * 11) | Should -BeGreaterThan 30\n      }      \n    }\n    Context 'Test Group 4 - String tests' {\n      $testValue = 'ArcaneCode'\n      # Test using a Like (not case senstive)\n      It \"Testing to see if $testValue has arcane\" {\n        $testValue | Should -BeLike \"arcane*\"\n      }\n    \n      # Test using cLike (case sensitive)\n      It \"Testing to see if $testValue has Arcane\" {\n        $testValue | Should -BeLikeExactly \"Arcane*\"\n      }\n    }\n    Context 'Test Group 5 - Array Tests' {\n      $myArray = 'ArcaneCode', 'http:\/\/arcanecode.red', 'http:\/\/arcanecode.me'\n      It 'Should contain ArcaneCode' {\n        $myArray | Should -Contain 'ArcaneCode'\n      }\n      It 'Should have 3 items' {\n        $myArray | Should -HaveCount 3\n      }\n    }\n}<\/pre>\n\n\n\n<p>&nbsp;<\/p>\n\n\n\n<p>Whew, that\u2019s a lot of tests! In fact, it won\u2019t be at all uncommon for your tests files to contain many, many tests. Indeed, the number of lines in your test scripts will often far exceed the number lines in the code being tested. Before analyzing the sample, look at the effect the use of Context had on the output.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"665\" height=\"664\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-60.png\" alt=\"\" class=\"wp-image-80425\"\/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<p>The use of <strong>Context<\/strong> broke the results into nice, easy to read sections. Rather than just line after line of tests, you can easily see the results broken into logical groups. Now look at some of the tests that were performed.<\/p>\n\n\n\n<p>Test Group 1 resembled tests performed in the opening section of this article. However, you can shortcut the use of <strong>Should -Be $true<\/strong> by using the <strong>-BeTrue<\/strong> switch. Likewise, there is a <strong>-BeFalse <\/strong>switch. In Test Group 2, you\u2019ll see that Pester also supports negative assertions. Simply add a <strong>-Not<\/strong> switch prior to the call to the <strong>Be<\/strong> switch, as was shown with Should <strong>-Not -BeTrue<\/strong>.<\/p>\n\n\n\n<p>In Test Group 3, you\u2019ll see how Pester handles calculated values. In addition to the <strong>BeGreater&#8230;<\/strong> switches there are also <strong>BeLess&#8230;<\/strong> versions of the switches. In the last example in this section, an actual calculation is piped into the <strong>Should<\/strong> function. When doing so, you must enclose your entire calculation in parenthesis. This forces PowerShell to do the calculation, then pass the result into the <strong>Should<\/strong>.<\/p>\n\n\n\n<p>Pester also supports testing of string values, as demonstrated in Test Group 4. A simple test is to use the <strong>like<\/strong> operator under the covers for wild card matches, with one version for case insensitive and another for case sensitive. Although not shown, you can also use the <strong>Be<\/strong> switch for string comparisons.<\/p>\n\n\n\n<p>In the last test group, number five, contains some tests for arrays, ascertaining if an array contains a certain value as well as ensuring the array has a specific count.<\/p>\n\n\n\n<p>While these are some of the most common <strong>Should<\/strong> tests you can perform, it is by no means a comprehensive list. There are switches for working with files, regular expressions, and more. You can find a complete list at the Pester <a href=\"https:\/\/github.com\/pester\/Pester\/wiki\/Should\">wiki<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-summary\">Summary<\/h2>\n\n\n\n<p>This article covered the basics of Pester. Using just what you\u2019ve learned here, you can begin testing your PowerShell scripts. Don\u2019t be fooled though, Pester provides an incredibly rich framework for testing. Future articles will cover such things as:<\/p>\n\n\n<div class=\"block-core-list\">\n<ul class=\"wp-block-list\">\n<li>Using Mocks in tests<\/li>\n\n\n\n<li>Multiple Describe blocks in tests, and adding tags to them<\/li>\n\n\n\n<li>Critical things to know in testing Modules<\/li>\n\n\n\n<li>Advanced options for invoking Pester tests<\/li>\n<\/ul>\n<\/div>\n\n\n<p>Go forth and begin Pestering your own PowerShell code, and check back soon for more articles full of Pester goodness.<\/p>\n\n\n\n<section id=\"faq\" class=\"faq-block my-5xl\">\n    <h2>FAQs: Testing PowerShell Code with Pester<\/h2>\n\n                        <h3 class=\"mt-4xl\">1. What is Pester in PowerShell?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Pester is an open\u2011source testing framework for PowerShell that lets you write and run automated tests for your scripts and modules. It helps ensure your code works as expected and catches regressions early.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">2. Why should I test PowerShell scripts with Pester?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Testing with Pester gives confidence that your code meets requirements, doesn\u2019t break other functions, and behaves correctly across changes &#8211; essential in automation and DevOps workflows.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">3. What types of tests can I write with Pester?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Pester supports unit testing, integration testing, and acceptance testing so you can validate individual components, their interactions, and full\u2011end functionality.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">4. How do I install or update Pester?<\/h3>\n            <div class=\"faq-answer\">\n                <p data-start=\"1124\" data-end=\"1197\">Use the PowerShell Gallery:<\/p>\n<p data-start=\"1124\" data-end=\"1197\"><code>Install-Module Pester -Force -SkipPublisherCheck <\/code><br \/>\n<code>Get-Module Pester -ListAvailable<\/code><\/p>\n<p data-start=\"1124\" data-end=\"1197\">This ensures you have the latest version available.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">5. How do I run Pester tests?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Use <code data-start=\"1433\" data-end=\"1448\">Invoke-Pester<\/code>, pointing to a test script (<code data-start=\"1477\" data-end=\"1490\">*.Tests.ps1<\/code>) or a directory to execute all tests in that folder.<\/p>\n            <\/div>\n                    <h3 class=\"mt-4xl\">6. What is a basic Pester test structure?<\/h3>\n            <div class=\"faq-answer\">\n                <p data-start=\"1583\" data-end=\"1651\">A basic test uses:<\/p>\n<ul data-start=\"1652\" data-end=\"1793\">\n<li data-start=\"1652\" data-end=\"1681\">\n<p data-start=\"1654\" data-end=\"1681\"><code data-start=\"1654\" data-end=\"1664\">Describe<\/code> to group tests<\/p>\n<\/li>\n<li data-start=\"1682\" data-end=\"1715\">\n<p data-start=\"1684\" data-end=\"1715\"><code data-start=\"1684\" data-end=\"1688\">It<\/code> to define each test case<\/p>\n<\/li>\n<li data-start=\"1716\" data-end=\"1793\">\n<p data-start=\"1718\" data-end=\"1793\"><code data-start=\"1718\" data-end=\"1726\">Should<\/code> to assert expected outcomes.<\/p>\n<\/li>\n<\/ul>\n            <\/div>\n                    <h3 class=\"mt-4xl\">7. Can I test for both passing and failing conditions with Pester?<\/h3>\n            <div class=\"faq-answer\">\n                <p>Yes &#8211; Pester lets you write tests that assert both success and expected failures to validate correct behavior under different scenarios.<\/p>\n            <\/div>\n            <\/section>\n\n\n\n<section id=\"my-first-block-block_5fe619035ed73106da6ec94dd9bc3c5f\" class=\"my-first-block alignwide\">\n    <div class=\"bg-brand-600 text-base-white py-5xl px-4xl rounded-sm bg-gradient-to-r from-brand-600 to-brand-500 red\">\n        <div class=\"gap-4xl items-start md:items-center flex flex-col md:flex-row justify-between\">\n            <div class=\"flex-1 col-span-10 lg:col-span-7\">\n                <h3 class=\"mt-0 font-display mb-2 text-display-sm\">Subscribe to the Simple Talk newsletter<\/h3>\n                <div class=\"child:last-of-type:mb-0\">\n                                            Get selected articles, event information, podcasts and other industry content delivered straight to your inbox every two weeks.                                    <\/div>\n            <\/div>\n                                            <a href=\"https:\/\/www.red-gate.com\/simple-talk\/subscribe\/\" class=\"btn btn--secondary btn--lg\" aria-label=\"Subscribe now: Subscribe to the Simple Talk newsletter\">Subscribe now<\/a>\n                    <\/div>\n    <\/div>\n<\/section>","protected":false},"excerpt":{"rendered":"<p>Everyone knows how important code testing is, and to be thorough, you must automate testing. This includes scripts such as those written in PowerShell as well. In this article, Robert Cain introduces Pester, a tool for testing PowerShell code.&hellip;<\/p>\n","protected":false},"author":316962,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":true,"footnotes":""},"categories":[53,35],"tags":[95506],"coauthors":[52865],"class_list":["post-80418","post","type-post","status-publish","format-standard","hentry","category-featured","category-powershell","tag-automate"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80418","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/users\/316962"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=80418"}],"version-history":[{"count":5,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80418\/revisions"}],"predecessor-version":[{"id":108152,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80418\/revisions\/108152"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=80418"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=80418"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=80418"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=80418"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}