{"id":80547,"date":"2018-08-30T13:20:39","date_gmt":"2018-08-30T13:20:39","guid":{"rendered":"https:\/\/www.red-gate.com\/simple-talk\/?p=80547"},"modified":"2019-01-22T16:49:08","modified_gmt":"2019-01-22T16:49:08","slug":"advanced-testing-of-your-powershell-code-with-pester","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/advanced-testing-of-your-powershell-code-with-pester\/","title":{"rendered":"Advanced Testing of 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<p>In part 1 of this series, <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>, I covered the basics of using the Pester module to test your PowerShell code. The types of testing, unit, integration, and acceptance were discussed. In addition, the importance of having good requirements was stressed. We rolled up our sleeves next, learning how to install Pester, invoke a Pester test, and how to construct a test using the <strong>Describe<\/strong>, <strong>Context<\/strong>, and <strong>It<\/strong> functions.<\/p>\n<p>In this article, we\u2019ll continue our journey with Pester. I had mentioned the concept of <strong>mocks<\/strong> in the previous article, in this one you\u2019ll see what a mock is and how to use it. I\u2019ll also introduce a new concept, <strong>TestPath<\/strong>. Next, I\u2019ll cover the way to distinguish the different types of test within Pester, and how to code your tests appropriately.<\/p>\n<h2>The Demos<\/h2>\n<p>The demos are in the same location on the author\u2019s <a href=\"https:\/\/github.com\/arcanecode\/PowerShell\/tree\/master\/PesterBasics\">GitHub repository<\/a> as the previous article. Locally, I continue to use the same <em>C:\\PowerShell\\Pester-Demo<\/em> folder as the previous article. 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<pre class=\"lang:ps theme:powershell-ise\">$dir = 'C:\\PowerShell\\Pester-Demo' <\/pre>\n<h2>Pretend to Do Something!<\/h2>\n<p>Before you can run a test, you need something to test. For this section on mocks, a function called <strong>PretendToDoSomething<\/strong> has been created. The basic requirements for this function are:<\/p>\n<ol>\n<li>Accept the name of the file you need to create.<\/li>\n<li>Check to see if the file already exists. If it does, give a warning and have the function return <strong>false<\/strong>.<\/li>\n<li>Read data from a database, do some calculations, then write the results to the output file name provided in the parameter.<\/li>\n<li>Return <strong>true<\/strong> to indicate everything went well.<\/li>\n<\/ol>\n<p>To explain mocks, you don\u2019t really need to create a function that does everything, so step 3 will be simulated using <strong>Write-Verbose<\/strong> statements. Let\u2019s look at the code; you\u2019ll find this code in the file <em>Mocks-PretendToDoSomething.ps1<\/em> in the demo downloads folder.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\"># Function to test Mocks with\r\nfunction PretendToDoSomething ()\r\n{\r\n  [CmdletBinding()]\r\n  param\r\n  (\r\n    [parameter (Mandatory = $true) ]\r\n    $OutputFile\r\n  )\r\n  # For demo purposes, we're going to pretend to read \r\n  # from a database, do some calculations, and create a file.\r\n  \r\n  # First though, we're going to check to see if the target file\r\n  # exists and if so warn the user and exit the function\r\n  Write-Verbose \"Checking to see if $OutputFile exists\"\r\n  $exists = Test-Path $OutputFile\r\n  if ($exists)\r\n  { \r\n    Write-Warning \"Output file $OutputFile already exists!\"\r\n    return $false\r\n  }\r\n    \r\n  # We're going to pretend, for this demo, that the Write-Verbose\r\n  # statements are really a long series of complex code we've written.\r\n  # In a non-demo situation this area is the code we really care about\r\n  # testing. \r\n  Write-Verbose 'Pretending to read data from a database'\r\n  Write-Verbose 'Pretending to do some calculations'\r\n  Write-Verbose \"Pretending to write our results to the file $OutputFile\"\r\n  return $true\r\n} <\/pre>\n<p>For the first test, you must create a <strong>unit test<\/strong>. If you recall, unit tests are done in isolation. They only run the code that is part of the module, not external code. For the function above, there is one line of code that must be addressed.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $exists = Test-Path $OutputFile<\/pre>\n<p><strong>Test-Path<\/strong> is a PowerShell cmdlet. In order to keep to the isolation principle, you need to replace it with your own call, and you can do so using a mock.<\/p>\n<div class=\"note\">\n<p><em>NOTE: Some might also argue cmdlets such as <strong>Write-Verbose<\/strong> or <strong>Write-Host<\/strong> would also violate isolation rules. And while they might be correct, at some point you must use cmdlets so foundational, that you just need to accept them. Many of the <strong>Write-*<\/strong> cmdlets would fall into this category. As stated earlier, when using <strong>Test-Path<\/strong><code>,<\/code> there are numerous things that may go wrong such as missing drives or folders. By mocking it, you remove the need to spend time debugging for those types of environmental conditions.<\/em><\/p>\n<\/div>\n<p>Ultimately, you\u2019ll need to decide which cmdlets are foundational and can safely skip testing \/ mocking, and which ones may, through potential bugs or being vulnerable to external conditions such as missing internet, drives, etc., need to be tested and \/ or mocked in your code.<\/p>\n<h2>Unit Tests with The Mock<\/h2>\n<p>It\u2019s time to create the test. If you want to follow along you can always download the complete file from the GitHub site as <em>Mocks-PretendToDoSomething.Tests.ps1<\/em>. At the top of the test, you\u2019ll find this code:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">$dir = 'C:\\PowerShell\\Pester-Demo'\r\nSet-Location $dir\r\n. \"$dir\\Mocks-PretendToDoSomething.ps1\"<\/pre>\n<p>Every time the test executes, it will set the location then execute the code to load the function in memory. This is important! Let\u2019s say your previous test found an error. You make changes to respond to the error, when you rerun the test you want to be sure your latest code is what is in memory. Hence it is important to execute your scripts in order to load, or reload, the items you are testing into memory.<\/p>\n<p>Next, call Pester\u2019s <strong>Describe <\/strong>function, and provide a name. Since these will be the unit tests, the name provided to the describe function reflects this. The next line creates a file name that doesn\u2019t exist and places it in memory. As you will see in a moment, the file name is irrelevant as, thanks to mocks, you will never be using it for this set of tests.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Describe 'Unit Tests' {\r\n  # Create a file name which doesn't exist\r\n  $aFileThatDoesntExist = 'C:\\blah\\blah\\blah\\fooey.txt'<\/pre>\n<p>Now it\u2019s time to employ Pester\u2019s<strong> mock<\/strong> function. When the <strong>PretendToDoSomething<\/strong><code> <\/code>function runs, you don\u2019t want it to actually call <strong>Test-Path<\/strong>, as calling functions outside of what the developer has coded violates the rule of isolation. Therefore, you need to provide a replacement function for PowerShell to call. Here is the mock to do that.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  # Test 1, make sure function returns false if file exists\r\n  # Make test-path indicate the file already exists\r\n Mock Test-Path { return $true }<\/pre>\n<p>You employ the Pester function <strong>Mock<\/strong>, then provide a replacement function with the same name as the cmdlet (or function from another script or module) you are substituting. When the test runs, instead of executing the real PowerShell <strong>Test-Path<\/strong> cmdlet, it will instead execute the code block you provide to the mock. In this case, the code simply returns the value of <strong>true<\/strong> which essentially lies to PowerShell and indicates the file already exists, even though it doesn\u2019t.<\/p>\n<p>While the code in the script block passed to the mock is very simple, just a single line of code, you can in fact make these as long and complex as you need them to be. For this test, simply returning <strong>true<\/strong> meets the requirements in the first test, listed below, because it tests to ensure the <strong>PretendToDoSomething<\/strong> function exits with a value of <strong>false<\/strong> if the file exists.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  $aTestResult = PretendToDoSomething $aFileThatDoesntExist -Verbose\r\n  It 'Returns False if file already exists' {\r\n    $aTestResult | Should -BeFalse\r\n  }<\/pre>\n<p>The <strong>PretendToDoSomething<\/strong> function is called and the result is placed in the <strong>$aTestResult<\/strong> variable. Within the<strong> PretendToDoSomething<\/strong> function, if <strong>Test-Path<\/strong> finds the file, it provides a warning and returns a value of<strong> false<\/strong>. With the test done by the<strong> It<\/strong> function, it ensures the function correctly returns <strong>false<\/strong> if the file is already present. You\u2019ll also note the use of the <strong>-Verbose <\/strong>switch to display additional information. When running tests manually this can be a useful tool for uncovering any errors. If you are running this in an automated fashion, for example as part of your source code management, then the verbose switch should be removed.<\/p>\n<p>By using a mock, you can easily test that the code correctly handles the condition of a file existing without actually needing to create a file, nor exposing any bugs that may be lurking in the <strong>Test-Path <\/strong>cmdlet. You are only testing the code within the <strong>PretendToDoSomething<\/strong> function.<\/p>\n<h2>Run the Tests<\/h2>\n<p>In the downloads you\u2019ll find a script <em>Invoke-MocksTests.ps1<\/em>. The code in it is straightforward.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\"># Set tests location\r\n$dir = 'C:\\PowerShell\\Pester-Demo'\r\nSet-Location $dir\r\n# Invoke all the tests in the file\r\nInvoke-Pester \"$dir\\Mocks-PretendToDoSomething.Tests.ps1\"<\/pre>\n<p>&nbsp;<\/p>\n<p>Here is the output when just the first test is added to the <em>Mocks-PretendToDoSomething.Tests.ps1<\/em>file:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"793\" height=\"228\" class=\"wp-image-80569\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-119.png\" \/><\/p>\n<p>The script provided the <em>Warning<\/em> from the <strong>PretendToDoSomething<\/strong> function, then returned <strong>false<\/strong> because, through the use of the mocked <strong>Test-Path<\/strong>, the code thought the file already existed.<\/p>\n<h2>Testing for the Other Condition<\/h2>\n<p>The first test made sure the<strong> PretendToDoSomething <\/strong>function correctly returned a warning and exited returning a value of<strong> false <\/strong>when the file name passed in the functions parameter already existed. But when writing tests, you need to test for <em>all conditions<\/em>. In this case there are only two, the file exists, which was tested for, or the file doesn\u2019t exist. For the \u2018file doesn\u2019t exist test\u2019 we\u2019ll use mock again and create a second version of <strong>Test-Path<\/strong>, only this time it will return <strong>false<\/strong> so the<strong> PretendToDoSomething <\/strong>function will think the file doesn\u2019t exist. You can then check the results with another <strong>It<\/strong> test.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">   # Test 2, make sure function returns true if file doesn't exist\r\n   # Make test-path indicate the file doesn't exist\r\n  Mock Test-Path { return $false }\r\n  \r\n  # Calling with verbose can aid in testing\r\n  $aTestResult = PretendToDoSomething $aFileThatDoesntExist -Verbose\r\n  It 'Returns True if file didnt exist and processed OK' {\r\n    $aTestResult | Should -BeTrue\r\n  }<\/pre>\n<p>Running the <em>Invoke-MockTests.ps1<\/em> now returns following results.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"805\" height=\"335\" class=\"wp-image-80570\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-120.png\" \/><\/p>\n<p>You can now see the two tests pass, the first testing for the file already existing, the second for when the file didn\u2019t exist. The unit test now tests for both possibilities.<\/p>\n<p>Obviously, this is a very simplified example; a real test would test many things beyond just the file existence, and likely include other mocks. There might be one mock for reading from the database, and another mock for writing out the file results, for example.<\/p>\n<h2>Integration Tests with $TestDrive<\/h2>\n<p>In the previous section, you saw how to construct tests that run in isolation, using the mock function to avoid executing code that was not part of the developers code base, such as code from PowerShell itself or modules such as AzureRM or SQLServer. The next step in testing is <em>Integration Testing<\/em>. With integration tests, you want to execute all code, both yours and that written by others. However, you want to eliminate any permanent effects, in other words not leaving any evidence your tests ran such as stray files, records in a database, and the like.<\/p>\n<p>With databases you might start with a database located on a test server that is in a <em>known state<\/em>. In other words, you know exactly what records are in it prior to the start of the test, what the tables look like, etc. This known state is often referred to as the <em>gold copy<\/em>. After the test, you can examine the state of the database, comparing it to the gold copy, to ensure it is as desired. Validate which rows were updated, table structures, and the like. At the end of the test your script would have code to drop the database and restore it from the gold copy, ready to begin the tests again, or alternatively as the first thing in all tests drop and restore from the gold copy.<\/p>\n<p>When it comes to eliminating effects to the file system, Pester makes this very easy. Rather than having to \u2018clean up,\u2019 Pester has a built-in variable called <strong>$TestDrive<\/strong>. When Pester runs a test, it generates a temporary area on your hard drive for this test execution, and places that location in the <strong>$TestDrive<\/strong> variable. Within your tests, you can reference the <strong>$TestDrive<\/strong> variable, much like the <strong>$dir<\/strong> variable is used in the downloaded samples. Before learning how to use this, first you need to update the <strong>PretendToDoSomething<\/strong> function. At the end of the function comment out the last <strong>Write-Verbose<\/strong> which pretends to write code to a file, and replace it with code that pushes a text string into a file using the <strong>Out-File<\/strong> cmdlet.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  # Write-Verbose \"Pretending to write our results to the file $OutputFile\"  \r\n  Write-Verbose \"Really writing our results to the file $OutputFile\"\r\n  \"Some text was written at $(Get-Date)\" | Out-File $OutputFile<\/pre>\n<p>Again, this simple snippet is just for illustration purposes, in your real-world code you\u2019d actually put something meaningful here. Now you\u2019re almost ready to write the integration tests. Unfortunately, the script for the unit tests is now broken. The use of <strong>Out-File<\/strong> will now violate the isolation testing rules, so you need to add it to the list of mocks within the original unit tests. You don\u2019t want it to actually do anything, so you can just have it be an empty function. Here is the revised Test 2 from the <strong>Unit Test<\/strong> describe block:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">  # Test 2, make sure function returns true if file doesn't exist\r\n  # Make test-path indicate the file doesn't exist\r\n  Mock Test-Path { return $false }\r\n  Mock Out-File { }\r\n  # Calling with verbose can aid in testing\r\n  $aTestResult = PretendToDoSomething $aFileThatDoesntExist -Verbose\r\n  It 'Returns True if file didnt exist and processed OK' {\r\n    $aTestResult | Should -BeTrue\r\n  }<\/pre>\n<p>As you can see, the only thing you had to do was mock the <strong>Out-File<\/strong> cmdlet. Now that the unit tests are running in isolation again, they will pass. This illustrates a good point, namely that changes to the code you are testing will often require changes to all of your tests, unit, integration, and acceptance.<\/p>\n<p>Now look at the code for the integration test. Add this code to the <em>Mocks-PretendToDoSomething.Tests.ps1<\/em> file.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Describe 'Integration Tests' {\r\n  # Create a file name \r\n  $myTestData = \"$($TestDrive)\\MyTestData.txt\"\r\n  # Test using a file name that won't exist\r\n  $aTestResult = PretendToDoSomething $myTestData\r\n  It 'Returns True if file didnt exist and processed OK' {\r\n    $aTestResult | Should -BeTrue\r\n  }\r\n  It \"See if the output file $myTestData now exists\" {\r\n    $myTestData | Should -Exist\r\n  }\r\n} <\/pre>\n<p>The <strong>Describe<\/strong> block appropriately uses the name <strong>Integration Tests<\/strong>. The next line is the key, here it references the Pester built in variable <strong>$TestDrive<\/strong> and appends a file name to use. Now you\u2019re going to call two tests. Note you do not use mocks here, you want the <strong>Test-Path<\/strong> and <strong>Out-File<\/strong> cmdlets in the <strong>PretendToDoSomething<\/strong> function to actually execute.<\/p>\n<p>In the first test, you are passing in a file name that shouldn\u2019t exist. And it won\u2019t; the <strong>$TestDrive<\/strong> location is created on your hard drive the first time it is called from within a <strong>Describe<\/strong> script block. It will remain until the end of the script block. You can be assured the file name contained in the <strong>$myTestData<\/strong> variable will not exist. This variable is passed into the <strong>PretendToDoSomething<\/strong> function. It should successfully get past the <strong>Test-Path<\/strong>, write to the file using <strong>Out-File<\/strong>, and then return <strong>true<\/strong>. The second test employs the <strong>Should -Exist<\/strong> function and switches to validate that the file was created. Execute the test by once again running the code in the <em>Invoke-MocksTests.ps1<\/em> script.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"818\" height=\"454\" class=\"wp-image-80571\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-121.png\" \/><\/p>\n<p>In the Integration Tests area, you\u2019ll see both tests passed. In addition, you\u2019ll see the long path which includes a GUID in the name in the second test. If you go hunting for this file on your hard drive, you won\u2019t find it. The moment PowerShell found the closing squiggly brace in the <strong>Describe<\/strong> script block, Pester deleted that <strong>TestDrive<\/strong> folder. In this example, the full path and file name were included so you could see the type of path that is created by <strong>TestDrive<\/strong>. In normal test results though you would not want to include this information as it is meaningless, so the next example will fix that as well as add a second test for when the file already exists.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Describe 'Integration Tests' {\r\n  # Create a file name \r\n  # $myTestData = \"$($TestDrive)\\MyTestData.txt\"\r\n  # Create a file name (revised)\r\n  $myTestDataFile = 'MyTestData.txt'\r\n  $myTestData = \"$($TestDrive)\\$($myTestDataFile)\"\r\n  \r\n  # Test using a file name that won't exist\r\n  $aTestResult = PretendToDoSomething $myTestData\r\n  It 'Returns True if file didnt exist and processed OK' {\r\n    $aTestResult | Should -BeTrue\r\n  }\r\n  # It \"See if the output file $myTestData now exists\" {\r\n  #   $myTestData | Should -Exist\r\n  # }\r\n  # Exist test revised to show just the file name\r\n  It \"See if the output file $myTestDataFile now exists\" {\r\n    $myTestData | Should -Exist\r\n  }\r\n  # Added test to see if file exists\r\n  $aTestResult = PretendToDoSomething $myTestData\r\n  It \"Returns False if $myTestDataFile existed\" {\r\n    $aTestResult | Should -BeFalse\r\n  }\r\n} <\/pre>\n<p>First, there is a variable declared to hold just the file name (<strong>$myTestDataFile<\/strong>). Then the <strong>$myTestData<\/strong> variable assignment was revised to use <strong>$TestDrive<\/strong> and the new <strong>$myTestDataFile<\/strong> variable. The second test was revised to show just the file name, not the full path and file.<\/p>\n<p>Finally, another was added test for when the file already exists. The file was created with the first test, so you can just reuse it with the second test where it checks for its existence. Alternatively, you could have also chosen to create the file yourself and used that file name as a parameter to the function being tested. Take a look at the output.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"819\" height=\"493\" class=\"wp-image-80572\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-122.png\" \/><\/p>\n<p>All three integration tests passed successfully. Also, for this test the Verbose switch was left off, just to show what a test looks like without using it.<\/p>\n<h2>Acceptance Tests<\/h2>\n<p>Thus far you\u2019ve seen two of the three types of tests, so now you\u2019ll address <em>acceptance tests<\/em>. With these types of tests, it is not only acceptable but desired to let the results of tests remain behind. Therefore, any files created should remain at the end of the test, unlike integration tests where nothing should remain behind when the tests are done. Here is the code for the acceptance tests.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Describe 'Acceptance Tests' {\r\n  # Setup a location and file name for testing\r\n  $dir = \"C:\\PowerShell\\Pester-Demo\"\r\n  $testFile = 'AcceptanceTestData.txt'\r\n  $testFilePath = \"$dir\\$testFile\"\r\n  # Ensure the file wasn't left over from a previous test\r\n  if ($(Test-Path $testFilePath))\r\n  {\r\n    # Delete it, don't ask for confirmation\r\n    Remove-Item $testFilePath -Force -ErrorAction SilentlyContinue\r\n  }\r\n  # Test using a file name that won't exist\r\n  $aTestResult = PretendToDoSomething $testFilePath\r\n  It 'Returns True if file didnt exist and processed OK' {\r\n    $aTestResult | Should -BeTrue\r\n  }\r\n  # Test for the existence of the output file\r\n  It \"See if the output file $testFilePath now exists\" {\r\n    $testFilePath | Should -Exist\r\n  }\r\n  # Added test to see if file exists\r\n  $aTestResult = PretendToDoSomething $testFilePath\r\n  It \"Returns False if $testFilePath existed\" {\r\n    $aTestResult | Should -BeFalse\r\n  }\r\n} <\/pre>\n<p>The test starts by designating a folder which already exists on the drive, and a file name. Note this does not use the <strong>$TestDrive<\/strong> folder, this is a real folder. This example uses the <em>C:\\PowerShell\\Pester-Demo<\/em> folder where the scripts reside.<\/p>\n<p>Next, it checks to see if the file exists, having been leftover from a previous test, and if so delete it. It then runs three tests. These three are identical to the ones used in the integration tests, with the exception of the variable names. Here is the output from running the tests:<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"828\" height=\"650\" class=\"wp-image-80573\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-123.png\" \/><\/p>\n<p>As you can see everything passed! Even better, if you look at the contents of the <em>C:\\PowerShell\\Pester-Demo <\/em>directory, you will see the <em>AcceptanceTestData.txt<\/em> file is still there.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"788\" height=\"296\" class=\"wp-image-80574\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-124.png\" \/><\/p>\n<p>Thanks to the inclusion of the <strong>Test-Path \/ Remove-Item<\/strong> code, you can run the test as many times as you wish; the code will clean up leftover files from any previous tests before it executes the test again.<\/p>\n<h2>Getting Selective with Tests<\/h2>\n<p>As you can see from the output, every time you run the tests, you are running all three types of tests: unit, integration, and acceptance. Most often though, you\u2019ll only want to run one, or maybe two of these types of tests. How then do you solve this dilemma?<\/p>\n<p>Well, you could of course break the tests into three separate files. You would then be forced to explicitly declare each file you wish to run. This is OK when you only have a few, but what if you had tens, or even hundreds of tests? It quickly becomes unmanageable. In addition, you have multiple tests files you have to update. Pester provides a better option, through the use of the <strong>Tag <\/strong>parameter on the <strong>Describe<\/strong> function. Return to the tests you created and update the <strong>Describe <\/strong>block declarations like so:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Describe 'Unit Tests' -Tag 'Unit' {\r\n \r\nDescribe 'Integration Tests' -Tag 'Integration' {\r\n \r\nDescribe 'Acceptance Tests' -Tag 'Acceptance' {<\/pre>\n<p>As you can see, a <strong>Tag<\/strong> parameter was added, followed by a string for the tag. Typically, you use a tag that described the type of test. However, this isn\u2019t a set rule. The <strong>Tag <\/strong>is just a string, you could have used any text you wished such as \u2018Arcane\u2019, \u2018Code\u2019, and \u2018Red Gate\u2019. It is generally best though to stick with something obvious as done here. Once you pick something, make it a standard, and use that across all your tests in your enterprise.<\/p>\n<p>Now you can return to the script where you invoke the tests. In the demos, this is the <em>Invoke-MocksTests.ps1<\/em>. Add the following line to it:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Invoke-Pester \"$dir\\Mocks-PretendToDoSomething.Tests.ps1\" -Tag 'Unit'<\/pre>\n<p>Now highlight the line in the ISE and either press F8, use File, Run Selection in the menu, or use the <img loading=\"lazy\" decoding=\"async\" width=\"21\" height=\"21\" class=\"wp-image-80575\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-125.png\" \/>button in the toolbar. When you do, in the output you\u2019ll see only the unit tests were executed.<\/p>\n<p><img loading=\"lazy\" decoding=\"async\" width=\"799\" height=\"363\" class=\"wp-image-80576\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/2018\/08\/word-image-126.png\" \/><\/p>\n<p>As you can see, only the describe block for unit tests was executed. Additionally, in the very first line of the output we see Pester outputs with the Tag<em> Unit<\/em> to show that it\u2019s only executing tests with <em>Describe<\/em> blocks having the Tag of <em>Unit<\/em>. You can repeat this for integration and acceptance tests.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Invoke-Pester \"$dir\\Mocks-PretendToDoSomething.Tests.ps1\" -Tag 'Integration'\r\nInvoke-Pester \"$dir\\Mocks-PretendToDoSomething.Tests.ps1\" -Tag 'Acceptance'<\/pre>\n<p>You can also include multiple tags on the Invoke-Pester call.<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">Invoke-Pester \"$dir\\Mocks-PretendToDoSomething.Tests.ps1\" -Tag 'Unit', 'Integration'<\/pre>\n<p>I\u2019ll leave it to you to execute and see the output.<\/p>\n<h2>Summary<\/h2>\n<p>This article began with a review of mocks, and how important they are to creating your unit tests. It then covered examples of unit, integration, and acceptance tests, and how Pester\u2019s <strong>TestDrive<\/strong> can assist you with creating integration tests. Finally, I wrapped this article up by showing how to <strong>Tag<\/strong> each of your test groups, and to invoke Pester so that it only executes tests with the specified tag or tags.<\/p>\n<p>In the next article, you\u2019ll see how to write Pester tests for your modules. It\u2019s not quite as straightforward as you might think, but once you learn the secret you\u2019ll be able to construct good tests for all your modules.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Testing your PowerShell scripts is just as important as testing any code. In this article, Robert Cain demonstrates how to use the testing tool, Pester, to perform unit, integration, and acceptance testing.&hellip;<\/p>\n","protected":false},"author":316962,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[53,35],"tags":[95506],"coauthors":[52865],"class_list":["post-80547","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\/80547","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=80547"}],"version-history":[{"count":12,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80547\/revisions"}],"predecessor-version":[{"id":81348,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/80547\/revisions\/81348"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=80547"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=80547"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=80547"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=80547"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}