{"id":1894,"date":"2014-11-05T00:00:00","date_gmt":"2014-11-04T00:00:00","guid":{"rendered":"https:\/\/test.simple-talk.com\/uncategorized\/practical-powershell-unit-testing-checking-program-flow\/"},"modified":"2016-07-28T10:47:04","modified_gmt":"2016-07-28T10:47:04","slug":"practical-powershell-unit-testing-checking-program-flow","status":"publish","type":"post","link":"https:\/\/www.red-gate.com\/simple-talk\/sysadmin\/powershell\/practical-powershell-unit-testing-checking-program-flow\/","title":{"rendered":"Practical PowerShell Unit-Testing: Checking program flow"},"content":{"rendered":"<div id=\"pretty\">\n<ul>\n<li>\n<div class=\"float-left\">&#160;<\/div>\n<div class=\"float-left\">     <a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/practical-powershell-unit-testing-getting-started\/\">PowerShell Unit-Testing: Getting Started<\/a><\/div>\n<\/li>\n<li>\n<div class=\"float-left\">&#160;<\/div>\n<div class=\"float-left\">     <a href=\"https:\/\/www.simple-talk.com\/sysadmin\/powershell\/practical-powershell-unit-testing-mock-objects\/\">Practical PowerShell Unit-Testing: Mock Objects<\/a><\/div>\n<\/li>\n<li>\n<div class=\"float-left\">&#9658;<\/div>\n<div class=\"float-left\">     Practical PowerShell Unit-Testing: Checking program flow<\/div>\n<\/li>\n<\/ul>\n<h2 id=\"first\">Contents<\/h2>\n<ul>\n<li><a href=\"#second\">Validating in a Test. <\/a><\/li>\n<li><a href=\"#third\">Call History. <\/a><\/li>\n<li><a href=\"#third\"><\/a><a href=\"#3fourth\">Validating Array Data. <\/a><\/li>\n<li><a href=\"#fifth\">Project Files. <\/a>\n<ul>\n<li><a href=\"#sixth\">Running the Module Tests. <\/a><\/li>\n<\/ul>\n<\/li>\n<li><a href=\"#seventh\">Pester Command Summary. <\/a><\/li>\n<li><a href=\"#3eighth\">Conclusion. <\/a><\/li>\n<\/ul>\n<p>Part one of this series explained how to install and use Pester, and the basic  structure of unit tests in PowerShell. Part two covered mocking and parameterized test cases. This final installment  focuses on validation, both with data and with program flow.<\/p>\n<h2 id=\"second\">Validating in a Test<\/h2>\n<p>I have touched on actual validation steps only implicitly in some of the  examples thus far. This section describes the important <code>Should<\/code> command (see  the Pester reference page at <a href=\"https:\/\/github.com\/pester\/Pester\/wiki\/Should\">https:\/\/github.com\/pester\/Pester\/wiki\/Should<\/a>).&#160; The canonical  verification assertion is:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t$actual=\"Actual value\"\n\t$actual | Should Be \"actual value\"&#160;&#160; # Passes\n\t$actual | Should Be \"other value\"&#160;&#160;&#160; # Throws a Pester Failure\n\t&#160;\n\t<\/pre>\n<p><code>Should<\/code>  offers a rich selection of operators, as detailed in the following two tables.<\/p>\n<table class=\"MsoTableMediumShading1Accent3\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p><code>Element<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p><code>Case Insensitive<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p><code>Case Sensitive<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Test that objects are the same<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Be<\/p>\n<\/td>\n<td valign=\"top\">\n<p>BeExactly<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Test that objects match by regex<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Match<\/p>\n<\/td>\n<td valign=\"top\">\n<p>MatchExactly<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Test that a file contains an item<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Contain<\/p>\n<\/td>\n<td valign=\"top\">\n<p>ContainExactly<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p> \t&#160;<\/p>\n<table class=\"MsoTableMediumShading1Accent3\">\n<tbody>\n<tr>\n<td valign=\"top\">\n<p><code>Element<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p><code>Operator<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p><code> \t\t\t&#160;<\/code><\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Test for null or empty string<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>BeNullOrEmpty<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\t\t&#160;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Test for object existence (akin to Test-Path)<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Exist<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\t\t&#160;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Test whether an exception was thrown<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Throw<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\t\t&#160;<\/p>\n<\/td>\n<\/tr>\n<tr>\n<td valign=\"top\">\n<p><code>Negate any of the above operators<\/code><\/p>\n<\/td>\n<td valign=\"top\">\n<p>Not<\/p>\n<\/td>\n<td valign=\"top\">\n<p> \t\t\t&#160;<\/p>\n<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>Note that earlier Pester versions-and earlier articles written about it-showed  this syntax, which is no longer valid:<\/p>\n<pre>\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;$actual.should.be(\"actual value\")  <\/pre>\n<div class=\"theory\"> \t<img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2084-pencil.jpg\" class=\"float-left\" alt=\"2084-pencil.jpg\" \/><\/p>\n<p><i>Use  the <code>Should<\/code> command to validate <code>scalar<\/code> data.<\/i><\/p>\n<\/p><\/div>\n<h2 id=\"third\">Call History<\/h2>\n<p>Besides validating that you get back an expected value, the next most common  thing to validate in a unit test is that a function <code>g<\/code> is called as a result of your calling a function <code> \tf<\/code>. Just as with standard .NET mocking framework moq (or others of its  ilk), you can verify whether a function or cmdlet was called in PowerShell by using Pester to mock it, run your action,  then check whether the mock was called. Here is the syntax for asserting that a mock was called:<\/p>\n<pre>\tAssert-MockCalled [ [-CommandName] &lt;String&gt; ]\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [-Exactly]\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [ [-Times] &lt;Int32&gt; ]\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; [ [-ParameterFilter] &lt;ScriptBlock&gt; ] \n\t<\/pre>\n<p>The simplest case is checking whether a mock was called or not, regardless of  the arguments passed to the function, and regardless of how many times it was called, use this simple form:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tAssert-MockCalled Select-String  <\/pre>\n<p>Contrariwise, if you wish to assert that a mock was never called, use the <code>-Times<\/code> parameter, specifying that it should be called zero times, hence not  at all:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tAssert-MockCalled Select-String -Times 0  <\/pre>\n<p>It is important to note that the count you supply to <code>-Times<\/code> indicates that the mock must be called <i>at least<\/i> that many times.&#160; Thus, to  assert that a mock was called <i>but only once<\/i>, add the <code>-Exactly<\/code> parameter:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tAssert-MockCalled Select-String -Exactly -Times 1  <\/pre>\n<p>Besides examining <i>how often<\/i> a mock was called, you can also check <i>how<\/i> a mock was  called, i.e. with what parameters. Say, for example, you wanted to confirm that <code>Select-String<\/code> was invoked with the  \t<code>SimpleMatch<\/code> switch parameter:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tAssert-MockCalled Select-String -ParameterFilter { $SimpleMatch -eq $true }  <\/pre>\n<p>When validating that functions or cmdlets were called, it is important to  consider scope. Say, for example, that you have multiple test (<code>It<\/code>) blocks  inside a <code>Context<\/code> block, as shown. You also declare a mock inside the <code>Context<\/code> scope but outside of either <code>It<\/code>  scope:<\/p>\n<pre class=\"lang:ps theme:powershell-ise mark:3\">\tDescribe &lt;test-name-string&gt; {\n\t&#160;&#160;&#160; Context &lt;context-description-string&gt; {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; Mock Get-Process\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It &lt;test-description-string&gt; {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Assert-MockCalled Get-Process ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160; \n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It &lt;test-description-string&gt; {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Assert-MockCalled Get-Process ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160; \n\t&#160;&#160;&#160; }\n\t}\n\t<\/pre>\n<p>You could (correctly) surmise that checking call history with <code>Assert-MockCalled<\/code> would fail in one or both tests because they would <i>both<\/i> be adding to the <i>same<\/i> mock&#8217;s history.<\/p>\n<p>But now consider moving the mock <i>inside<\/i>  the test scope (the <code>It<\/code> block), as shown below.&#160; Notice that each <code>It<\/code> block specifies the same mock.<\/p>\n<pre class=\"lang:ps theme:powershell-ise mark:4,9\">\tDescribe &lt;test-name-string&gt; {\n\t&#160;&#160;&#160; Context &lt;context-description-string&gt; {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It &lt;test-description-string&gt; {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Mock Get-Process\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Assert-MockCalled Get-Process ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160; \n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It &lt;test-description-string&gt; {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Mock Get-Process\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Assert-MockCalled Get-Process ...\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }&#160;&#160; \n\t&#160;&#160;&#160; }\n\t}\n\t<\/pre>\n<p>You would think the tests would now be completely independent-and correctly  validate the mock calls-but not so!&#160; The mocks are <i>still<\/i> scoped to the <code>Context<\/code> block!&#160; See my <a href=\"https:\/\/github.com\/pester\/Pester\/issues\/178\">forum post<\/a> on this important point. It turns out  that, as designed, <code>Assert-MockCalled<\/code> is scoped to its containing <code>Context<\/code> block (or if no <code>Context<\/code> block is present, then its  current <code>Describe<\/code> block), which is why the above tests will not work  correctly. I could see that that behavior is useful for some tests, but for others (like the example above) it would  really be useful to be able to scope a mock to an <code>It<\/code> block. As Dave Wyatt responded in my post referenced above, the new 3.0 release now provides just this  flexibility: the <code>-Scope<\/code> parameter. Thus, we need only change each <code>Assert-MockCalled<\/code>  above to specify scoping to the <code>It<\/code> block&#8230;<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tAssert-MockCalled Get-Process -Scope It ...  <\/pre>\n<p>&#8230; for the above two tests in the same <code>Context<\/code> block to correctly validate calls on the mock. I would recommend explicitly using the \t<code>Scope<\/code> parameter (which may be set to <code>It<\/code>, <code>Context<\/code>, or <code>Describe<\/code>)  on <i>all<\/i> <code>Assert-MockCalled<\/code> instances for clarity.<\/p>\n<div class=\"note\">\n<p class=\"note\"><i>Pester 3.0 note:<\/i>  Version 3.0 is brand new as I write so I have only experimented with it for a short time. According to the  documentation, a defined mock is still supposed to default to the closest <code>Context<\/code>  or <code>Describe<\/code> block, but my cursory test seems to show that a mock actually defaults to the block in which it is  defined, be it <code>It<\/code>, <code>Context<\/code>, or <code>Describe<\/code>. I found this out because my tests that had  failed with 2.0 started working with 3.0 before I even added a <code>-Scope It<\/code>.<\/p>\n<\/div>\n<p>There is one other command available for verifying call history: <code>Assert-VerifiableMocks<\/code>. With this command, you flag each mock you wish to  verify when you create the mocks. Then you invoke <code>Assert-VerifiableMocks<\/code> at  the end of your test to validate all the mocks you have flagged in one go. See the official Pester documentation for  more.<\/p>\n<div class=\"theory\"> \t<img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2084-pencil.jpg\" class=\"float-left\" alt=\"2084-pencil.jpg\" \/><\/p>\n<p><i>Use  \t<code>Assert-MockCalled<\/code> or <code>Assert-VerifiableMocks <\/code>to  validate program flow.<\/i><\/p>\n<\/p><\/div>\n<h2>Validating Array Data<\/h2>\n<p>Earlier you saw how to validate results with the <code>Should<\/code> command. Unfortunately, <code>Should<\/code>  \tdoes not always work for arrays.&#160;Consider the  \tfollowing tests:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tDescribe 'array techniques' {\n\t\n\t&#160;&#160;&#160; Context 'scenario 1' {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; $actual = 'a923e023.txt','ke923jd.txt'\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; $expected = 'a923e023.txt','something_else.txt', 'not_there.txt'\n\t\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It 'array check (native)' {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; $actual | Should Be $expected\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It 'array check (ArrayHelper)' {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ArrayDifferences $actual $expected | Should BeNullOrEmpty\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n\t&#160;&#160;&#160; }\n\t&#160;&#160;&#160; Context 'scenario 2' {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; $actual = 'something_else.txt'\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; $expected = 'a923e023.txt','something_else.txt', 'not_there.txt'\n\t\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It 'array check (native)' {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; $actual | Should Be $expected\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; It 'array check (ArrayHelper)' {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; ArrayDifferences $actual $expected | Should BeNullOrEmpty\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160; }\n\t&#160;&#160;&#160; }\n\t} \n\t\n\t<\/pre>\n<p>Scenario 1 is expecting three values but the actual comes back with only one  \tof those, plus one that was not expected. Within the <b>Context<\/b> block for  \tscenario 1, I have one test using the native <b>Should Be<\/b> and a second using a helper function I created for validating arrays. Here is the output for the  \ttwo tests in scenario 1:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;&#160; Context scenario 1\n\t&#160;&#160;&#160; [-] array check (native) 66ms\n\t&#160;&#160;&#160; &#160;&#160;&#160;&#160;Expected: {a923e023.txt something_else.txt not_there.txt}\n\t&#160; &#160;&#160;&#160;&#160;&#160;&#160;But was:&#160; {ke923jd.txt}\n\t&#160;&#160; &#160;&#160;&#160;&#160;&#160;at line: 64 in C:\\usr\\tmp\\HelloWorld.Tests.ps1\n\t&#160;&#160;&#160; [-] array check (ArrayHelper) 11ms\n\t&#160;&#160;&#160; &#160;&#160;&#160;&#160;Expected: value to be empty but it was\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {Surplus: ke923jd.txt &amp;&amp; Missing: something_else.txt,not_there.txt}\n\t&#160;&#160;&#160;&#160; &#160;&#160;&#160;at line: 67 in C:\\usr\\tmp\\HelloWorld.Tests.ps1\n\t<\/pre>\n<p>The native Pester approach does report some part of the problem but not the  \twhole problem. Using the <b>ArrayDifferences<\/b> function, on the other hand, clearly spells out what was unexpected in the actual result,  \tboth missing and surplus items. Scenario 2 highlights an even more serious flaw:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;&#160; Context scenario 2\n\t&#160;&#160;&#160; [+] array check (native) 72ms\n\t&#160;&#160;&#160; [-] array check (ArrayHelper) 8ms\n\t&#160;&#160;&#160;&#160;&#160; Expected: value to be empty but it was {Missing: a923e023.txt,not_there.txt}\n\t&#160;&#160;&#160;&#160;&#160; at line: 78 in C:\\usr\\tmp\\HelloWorld.Tests.ps1\n<\/pre>\n<p>Here, the native Pester test reports a passing result when it should be a  \tfailing result, as the <b>ArrayDifferences<\/b> version identifies.<\/p>\n<p><code>ArrayHelper <\/code>actually supplies two different functions for validating arrays,  \tshown below. Both are, in fact, testing the same thing-that the two arrays (<code>$actualResult<\/code> and  \t<code>$expectedResult<\/code>) are  \tequal:<\/p>\n<p>These two statements show the two helper functions. Both  are, in fact, testing the same thing-that the two arrays (<code>$actualResult <\/code>and<code> $expectedResult<\/code>) are equal:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tAreArraysEqual&#160;&#160; $actualResult $expectedResult | Should Be $true\n\tArrayDifferences $actualResult $expectedResult | Should BeNullOrEmpty\n\t<\/pre>\n<p>Both array helper functions compare arrays in an order-independent fashion. So  if the actual and expected differ only by order, as shown here, then both of these test statements will pass:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;&#160;&#160; AreArraysEqual&#160;&#160; @(12, -5) @(-5, 12) | Should Be $true\n\t&#160;&#160;&#160; ArrayDifferences @(12, -5) @(-5, 12) | Should BeNullOrEmpty\n<\/pre>\n<p>Where these two functions differ is when a failure occurs, i.e. when the two  arrays do not contain the same set of members. For this next example, assume we ended up with actual and expected arrays  as follows:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;&#160;&#160; $actualResult = 'nameA','nameB'\n\t&#160;&#160;&#160; $expectedResult = 'nameB','nameC','nameD','nameE',\n\t<\/pre>\n<p>Obviously these arrays differ so attempting to validate that they are equal will  report failure with both help functions. Here is what you would get:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;&#160;&#160; AreArraysEqual&#160;&#160; $actualResult $expectedResult | Should Be $true\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Expected: {True}, But was {False}\n\t&#160;&#160;&#160; ArrayDifferences $actualResult $expectedResult | Should BeNullOrEmpty\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Expected: value to be empty but it was\n&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; {Extras actual: nameA &amp;&amp; Extras expected: nameC,nameD,nameE}\n<\/pre>\n<p>Clearly, <code>ArrayDifferences<\/code> gives better quality output upon failure.&#160; When  the <code>Should BeNullOrEmpty<\/code> predicate receives something other than null or &#8220;&#8221;,  it reports <i>Expected value to be empty but it was <\/i><i> \tsomething<\/i>. <code>ArrayDifferences<\/code> populates <i>something<\/i>  with an empty string if the two arrays contain the same members. Otherwise, it enumerates the differences by reporting  which elements appeared in the actual list that were not in the expected list, and vice versa. Thus, in the case of  failure the test output directly reveals all the differences, obviating the need to fire up the debugger to uncover  those details.  \t \t<\/p>\n<p><code>AreArraysEqual<\/code>,  on the other hand, is quite bad from that perspective. It merely returns one bit of information: whether the two arrays  contain the same members. But <code>AreArraysEqual<\/code> has another use; you will see it  used liberally in one of the sample files like this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;Assert-MockCalled ReportMissing 1 { AreArraysEqual $items $missingList }  <\/pre>\n<p>You can read this statement as: <i>confirm  that <code>ReportMissing<\/code> was called at least once where its <code>$items<\/code> parameter  contained the values in our expected list, <code>$missingList<\/code>.<\/i><\/p>\n<p>Pester uses script block parameters frequently, you may have noticed, making it  quite flexible in what you can do. In the <i>Call History<\/i> section earlier, you  saw a more conventional value supplied to <code>ParameterFilter<\/code>, specifying that a parameter had a given value <code>({ $SimpleMatch -eq $true }).<\/code> With arrays,  though, you cannot specify a simple Boolean predicate to test an array for equality to some other array. But looking at  the <code>ParameterFilter<\/code> from a broader perspective, it is just a script block  that evaluates to a Boolean value. So you can use any arbitrary logic you like, so long as it returns a Boolean. In the  current example, we use <code>AreArraysEqual<\/code> for this purpose.  \t \t<\/p>\n<p>Finally, let us return to the example from part 2, wherein we tested the \t<b>Get-TextFileNames<\/b> function, and correct a hidden problem lurking in the  \tshadows. Here is the latest version we used:<\/p>\n<pre class=\"lang:ps theme:powershell-ise mark:22,30\">\tDescribe 'Get-TextFileNames' {\n\t\n\t&#160; ContextUsing \"file combinations\" (\n\t\n\t&#160;&#160;&#160; # Data for test #1\n\t&#160;&#160;&#160; ('a923e023.txt', # the $files parameter\n\t&#160;&#160;&#160;&#160; 'a923e023.txt', # the $expectedResult parameter\n\t&#160;&#160;&#160;&#160; 'one text file when that is all there is'), # the description parameter\n\t\n\t&#160;&#160;&#160; # Data for test #2\n\t&#160;&#160;&#160; (('a923e023.txt','wlke93jw3.doc'),\n\t&#160;&#160;&#160;&#160; 'a923e023.txt',\n\t&#160;&#160;&#160;&#160; 'one text file when there are assorted files'),\n\t\n\t&#160;&#160;&#160; # Data for test #3\n\t&#160;&#160;&#160; (('a923e023.txt','wlke93jw3.doc','ke923jd.txt','qq02000.doc'),\n\t&#160;&#160;&#160;&#160; ('a923e023.txt','ke923jd.txt'),\n\t&#160;&#160;&#160;&#160; 'multiple text files amongst assorted files'),\n\t\n\t&#160;&#160;&#160; # Data for test #4\n\t&#160;&#160;&#160; (('wlke93jw3.doc','qq02000.doc'),\n\t&#160;&#160;&#160;&#160;  $null,\n\t&#160;&#160;&#160;&#160; 'nothing when there are no text files')\n\t\n\t&#160; ) {\n\t&#160;&#160;&#160; param($files, $expectedResult, $description)\n\t\n\t&#160;&#160;&#160;&#160;&#160;&#160; It \"returns $description\" {\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Mock Get-ChildItem { CreateFileList $files }\n\t&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; Get-TextFileNames | Should Be $expectedResult\n\t&#160;&#160;&#160;&#160;&#160; }\n\t&#160; }\n\t}\n<\/pre>\n<p>With fresh insight you can now quickly surmise that \t<b>Should Be<\/b> on the highlighted line is trying to validate arrays. All four  \ttests were passing, but now you know you cannot necessarily trust that result! To make this more robust we need two  \tchanges. First, change the validation line to this:<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\tArrayDifferences @(Get-TextFileNames) $expectedResult | Should BeNullOrEmpty <\/pre>\n<p><b>ArrayDifferences<\/b>  \tpasses its two arguments to the built-in <b>Compare-Object<\/b> cmdlet, whose arguments must be arrays-a null value does not qualify! Thus, instead of  \t(Get-TextFileNames) \twe use&#160;  \t@(Get-TextFileNames)  \tto force an empty result to be an empty array rather than null.<\/p>\n<p>The second required change addresses the same point on the other argument, \t<b>$expectedResult<\/b>. Notice the highlighted \t<b>$null<\/b> in the fourth test: change that to an empty array,&#160; \t \t@( \t), to complete the changes to make this a robust set of unit tests.&#160;<\/p>\n<div class=\"theory\"> \t<img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2084-pencil.jpg\" class=\"float-left\" alt=\"2084-pencil.jpg\" \/><\/p>\n<p><i>You cannot use <code>Should<\/code> to validate array data.<\/i><\/p>\n<\/p><\/div>\n<h2 id=\"fifth\">Project Files<\/h2>\n<p>This series has described a variety of tweaks and techniques to streamline your  work with Pester. Attached to this article is a file archive that contains the helper functions discussed herein, along  with some sample source and test files so you can see how I have used Pester for some real-world code. Within the  archive are two main folders: one contains code that needs to be installed within the Pester installation itself  <code>(ContextHelper.ps1<\/code>) and the other contains a simple but real-world PowerShell module (<code>PesterArticleSample<\/code>) that contains  the module source code (<code>GetSafeProperty.ps1<\/code> and <code>ProjectFileConsistency.ps1<\/code>), the module infrastructure  (<code>PesterArticleSample.psm1<\/code> and <code>PesterArticleSample.psd1<\/code>),&#160; helper functions (<code>TestHelpers<\/code>  folder) and unit tests for all the code. You might want to review the preamble to each of the test files (<code>*.Tests.ps1<\/code>)  to see a couple different use cases for loading corresponding source. Here&#8217;s the content of the file archive, followed  by details on the &#8220;helper&#8221; files.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/www.red-gate.com\/simple-talk\/wp-content\/uploads\/imported\/2084-img10.jpg\" alt=\"2084-img10.jpg\" \/><\/p>\n<p><code>ContextHelper.ps1<\/code><\/p>\n<div class=\"indent\">\n<p>This file extends Pester itself by providing the <code>ContextUsing<\/code> command as described in <i>Parameterized Test Cases<\/i> in part two of this series. (Note that native support for parameterized tests in Pester is  imminent, which will provide a slightly different syntax for accomplishing the same thing. Keep an eye on the Pester  releases for this in the very near future.)<\/p>\n<ol>\n<li>Copy this file into the <code>Functions<\/code> subdirectory of your Pester installation.  \t<\/li>\n<li>Edit the Pester manifest (Pester.psd1 in the root of your Pester  installation) to add <code>ContextUsing<\/code> to the list of function names in <code>FunctionsToExport<\/code>.<\/li>\n<\/ol>\n<p>Then go ahead and load the Pester module. (If you have already loaded it, you  will need to reload it with the <code>-Force<\/code> parameter, i.e.  \tImport-Module -Force Pester to have it recognize the  update.)=&#8221;mono&#8221;&gt;<\/p>\n<\/div>\n<p><code>ArrayHelper.ps1<\/code><\/p>\n<div class=\"indent\">\n<p>This file provides the <code>ArrayDifferences<\/code> and <code>AreArraysEqual<\/code> functions discussed in \t<i>Validating Array Data <\/i>in part three of this series. It is included in the <code>tests<\/code> folder for the module. For your own projects, copy the file to a  location of your choice. I typically put its containing folder (<code>TestHelpers<\/code>)  in my <code>tests<\/code> directory to keep it separate from the tests yet near at hand so  it is easy to reference, as described in <i>Making your Test File Aware of Helper  Files<\/i> in part one.<\/p>\n<\/div>\n<h3 id=\"sixth\">Running the Module Tests<\/h3>\n<p>Go to the directory containing the sample module (or some ancestor) and run  Pester with these two commands:<\/p>\n<pre class=\"lang:ps theme:powershell-output\">\tPS&gt; Import-Module Pester\n\tPS&gt; Invoke-Pester\n\t&#160;\n<\/pre>\n<p>Here is the full test run. If you compare this to the test files themselves, you  can easily discern the <code>Describe<\/code> commands and <code>Context<\/code> commands. The individual <code>It<\/code>  commands are <i>not<\/i> noted explicitly in the output, but those are all the lines in green. Notice there is no visual  demarcation of <i>file<\/i> boundaries; you only have a list of the <i>functions<\/i> at the top level (presuming you use the Pester convention of specifying function names as the  description in the <code>Describe<\/code> commands).<\/p>\n<pre class=\"lang:ps theme:powershell-ise\">\t&#160;\n\tPS tests&gt; Import-Module Pester\n\tPS tests&gt; Invoke-Pester\n\tExecuting all tests in 'C:\\usr\\tmp\\PesterArticleSample'\n\tDescribing Get-SafeProperty\n\t&#160;&#160; Context for shallow property\n\t&#160;&#160;&#160; [+] returns value when property exists 328ms\n\t&#160;&#160;&#160; [+] returns default when empty property name specified 14ms\n\t&#160;&#160;&#160; [+] returns default when property does not exist 4ms\n\t&#160;&#160;&#160; [+] returns null when property does not exist and default not specified 4ms\n\t&#160;&#160; Context for deep property failure\n\t&#160;&#160;&#160; [+] returns default when no leaf specified 55ms\n\t&#160;&#160;&#160; [+] returns default when non-existent leaf specified 8ms\n\t&#160;&#160;&#160; [+] returns default when non-existent parent specified 5ms\n\t&#160;&#160; Context for deep property success\n\t&#160;&#160;&#160; [+] returns value when property exists (item.BaseItem.ChildItem) 53ms\n\t&#160;&#160;&#160; [+] returns value when property exists (item.BaseItem.OtherItem) 5ms\n\t&#160;&#160; Context for null object\n\t&#160;&#160;&#160; [+] returns default 54ms\n\t&#160;&#160; Context for deep property success on hashtable\n\t&#160;&#160;&#160; [+] returns value when property exists (item.BaseItem.ChildItem) 53ms\n\t&#160;&#160;&#160; [+] returns value when property exists (item.BaseItem.OtherItem) 5ms\n\tDescribing GetFilesLackingItem\n\t&#160;&#160; Context checks all or none\n\t&#160;&#160;&#160; [+] reports all files missing item when none of them pass select-string 290ms\n\t&#160;&#160;&#160; [+] reports no files missing item when all of them pass select-string 31ms\n\t&#160;&#160; Context checks some files\n\t&#160;&#160;&#160; [+] reports subset of files missing item 99ms\n\t&#160;&#160; Context checks match type\n\t&#160;&#160;&#160; [+] is simple match when requested 82ms\n\t&#160;&#160;&#160; [+] is regex match when requested 25ms\n\t&#160;&#160;&#160; [+] is regex match when not directed otherwise 24ms\n\t&#160;&#160; Context When project filter is present\n\t&#160;&#160;&#160; [+] filters Get-ChildItem 80ms\n\tDescribing GetFiles\n\t&#160;[+] reports files missing base item and from the remainder those with non-standard item 140ms\n\tDescribing ProcessTestItem\n\t&#160;&#160; Context when processing an item\n\t&#160;&#160;&#160; [+] processes test name 162ms\n\t&#160;&#160; Context Processes both missing and non-standard items\n\t&#160;&#160;&#160; [+] with implicit direction 102ms\n\t&#160;&#160; Context Processes both missing and non-standard items\n\t&#160;&#160;&#160; [+] with explicit direction 118ms\n\t&#160;&#160; Context Processes non-standard items\n\t&#160;&#160;&#160; [+] but skips missing items when directed 79ms\n\tDescribing Confirm-ProjectFileConsistency\n\t&#160;&#160; Context for a non-empty list\n\t&#160;&#160;&#160; [+] iterates over all items in test list 161ms\n\t&#160;&#160; Context for an empty list\n\t&#160;&#160;&#160; [+] iterates over no items 49ms\n\t&#160;&#160; Context for a test filter\n\t&#160;&#160;&#160; [+] iterates over only the matched items in test list 76ms\n\tDescribing ArrayDifferences\n\t&#160;&#160; Context for equivalent arrays\n\t&#160;&#160;&#160; [+] no differences when args are empty arrays 106ms\n\t&#160;&#160;&#160; [+] no differences when args are equal arrays 18ms\n\t&#160;&#160;&#160; [+] no differences when args are equal arrays in different order 7ms\n\t&#160;&#160; Context for surplus results\n\t&#160;&#160;&#160; [+] reports one surplus value over an empty array 63ms\n\t&#160;&#160;&#160; [+] reports multiple surplus values over an empty array 10ms\n\t&#160;&#160;&#160; [+] reports one surplus value over a non-empty array 10ms\n\t&#160;&#160;&#160; [+] reports multiple surplus values over a non-empty array 12ms\n\t&#160;&#160; Context for missing results\n\t&#160;&#160;&#160; [+] reports one missing value over an empty array 58ms\n\t&#160;&#160;&#160; [+] reports multiple missing values over an empty array 7ms\n\t&#160;&#160;&#160; [+] reports one missing value over a non-empty array 18ms\n\t&#160;&#160;&#160; [+] reports multiple missing values over a non-empty array 8ms\n\t&#160;&#160; Context for missing and surplus results\n\t&#160;&#160;&#160; [+] reports all actual as surplus and all expected as missing 56ms\n\t&#160;&#160;&#160; [+] reports one surplus and one missing 6ms\n\tTests completed in 2.5s\n\tPassed: 40 Failed: 0  \n\t&#160;\n<\/pre>\n<h2 id=\"seventh\">Conclusion<\/h2>\n<p>Though Pester is a rather small package and offers a relatively small number of  commands, it has tremendous capabilities for unit testing PowerShell code. Now that you have the tips and techniques  provided in this series of articles added to your arsenal, go out there and conquer your code!<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Pester offers a relatively small number of commands to Unit-test PowerShell scripts, but  these commands have tremendous capabilities. Pester even gives you the means to  validate data and test  program flow. It uses &#8216;mocks&#8217; to provide hooks to validate program flow, so you can be more confident that a function is doing things they way you intended.&hellip;<\/p>\n","protected":false},"author":221868,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[35],"tags":[4178,4635,4871],"coauthors":[],"class_list":["post-1894","post","type-post","status-publish","format-standard","hentry","category-powershell","tag-bi","tag-powershell","tag-sysadmin"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1894","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\/221868"}],"replies":[{"embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/comments?post=1894"}],"version-history":[{"count":7,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1894\/revisions"}],"predecessor-version":[{"id":66399,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/posts\/1894\/revisions\/66399"}],"wp:attachment":[{"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/media?parent=1894"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/categories?post=1894"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/tags?post=1894"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.red-gate.com\/simple-talk\/wp-json\/wp\/v2\/coauthors?post=1894"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}