<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Unit Archives - LucD notes</title>
	<atom:link href="https://www.lucd.info/category/powershell/pester/unit/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.lucd.info/category/powershell/pester/unit/</link>
	<description>My PowerShell ramblings</description>
	<lastBuildDate>Fri, 01 Feb 2019 14:04:15 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://www.lucd.info/wp-content/uploads/2018/12/cropped-120px-Tibetan_Dharmacakra-32x32.png</url>
	<title>Unit Archives - LucD notes</title>
	<link>https://www.lucd.info/category/powershell/pester/unit/</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/><atom:link rel="hub" href="https://websubhub.com/hub"/>	<item>
		<title>DSCR and Pester testing</title>
		<link>https://www.lucd.info/2019/02/01/dscr-and-pester-testing/</link>
					<comments>https://www.lucd.info/2019/02/01/dscr-and-pester-testing/#comments</comments>
		
		<dc:creator><![CDATA[LucD]]></dc:creator>
		<pubDate>Fri, 01 Feb 2019 13:27:19 +0000</pubDate>
				<category><![CDATA[DSCR]]></category>
		<category><![CDATA[Pester]]></category>
		<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Unit]]></category>
		<category><![CDATA[PowerCLI]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[vSphere]]></category>
		<guid isPermaLink="false">http://www.lucd.info/?p=6263</guid>

					<description><![CDATA[In my previous post DSCR for VMware and you! I described the open [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>In my previous post <a rel="noreferrer noopener" aria-label="DSCR for VMware and you! (opens in a new tab)" href="https://www.lucd.info/2018/12/16/dscr-for-vmware-and-you/" target="_blank">DSCR for VMware and you!</a> I described the open source project that was started to develop DSC resources for vSphere (DSCR). One of the requirements for contributing, is that you provide <strong>Unit</strong> and <strong>Integration</strong> <a rel="noreferrer noopener" aria-label="Pester (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Pester" target="_blank">Pester</a> tests for any new DSC resource you contribute to DSCR.</p>



<figure class="wp-block-image"><img fetchpriority="high" decoding="async" width="407" height="407" src="https://www.lucd.info/wp-content/uploads/2019/01/dscr-pester-logo.jpg" alt="" class="wp-image-6268" srcset="https://www.lucd.info/wp-content/uploads/2019/01/dscr-pester-logo.jpg 407w, https://www.lucd.info/wp-content/uploads/2019/01/dscr-pester-logo-150x150.jpg 150w, https://www.lucd.info/wp-content/uploads/2019/01/dscr-pester-logo-300x300.jpg 300w, https://www.lucd.info/wp-content/uploads/2019/01/dscr-pester-logo-170x170.jpg 170w" sizes="(max-width: 407px) 100vw, 407px" /></figure>



<p>The vSphere environment and <a rel="noreferrer noopener" aria-label="VMware PowerCLI (opens in a new tab)" href="https://code.vmware.com/tool/vmware-powercli/11.1.0" target="_blank">VMware PowerCLI</a> have some peculiarities that will require you to use some specific Pester techniques to write these Pester tests. This post should help you understand how this done. This is <strong>not</strong> intended as a <strong>Pester course</strong>, there are other, and better, resources for that.</p>



<span id="more-6263"></span>



<h2 class="wp-block-heading">Some Basics</h2>



<h3 class="wp-block-heading">Describe + It</h3>



<p>Since most of us are not regular or experienced Pester test writers, I will start with some basic concepts, before diving into more vSphere specific techniques. Just follow along.</p>



<p>From the <a rel="noreferrer noopener" aria-label="Pester Wiki (opens in a new tab)" href="https://github.com/pester/Pester/wiki" target="_blank">Pester Wiki</a> we learn that &#8221; <br><em>Pester is a Behavior-Driven Development (BDD) based test runner for PowerShell</em> &#8220;. One of the guiding principles in <a rel="noreferrer noopener" aria-label="BDD (opens in a new tab)" href="https://en.m.wikipedia.org/wiki/Behavior-driven_development" target="_blank">BDD</a> is &#8221; <br><em>&#8230; tests of any unit of software should be specified in terms of the desired behavior of the unit</em>&#8220;.<br>In short, we are going to write tests to verify that our code behaves as we expect it to behave, in all possible circumstances. And these tests will also allow us to verify that any future changes to the code do not break it.</p>



<p>In its most basic format, a Pester test consists of a <a rel="noreferrer noopener" aria-label="Describe (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Describe" target="_blank">Describe</a> block, a way of logically organising tests, and an <a rel="noreferrer noopener" aria-label="It (opens in a new tab)" href="https://github.com/pester/Pester/wiki/It" target="_blank">It</a> block, in which we assert a test. The word <strong>assert</strong> comes from the <a rel="noreferrer noopener" aria-label="Arrange-Act-Assert (opens in a new tab)" href="https://wiki.c2.com/?ArrangeActAssert" target="_blank">Arrange-Act-Assert</a> pattern.</p>



<p>Time to see some code. The following is a very simplistic test setup.</p>



<pre class="wp-block-code"><code>function Do-Something {
    return "Doing something"
}

Describe 'Test doing something' -Tag 'OurTest' {
    It 'Function called' {
        Do-Something | Should -Be 'Doing something'
    }
}</code></pre>



<p>We are testing a function <strong>Do-Something</strong>. For that we start a <strong>Describe</strong> block. In that block, we have one <strong>It</strong> block. And in that It block we <strong>assert</strong> that our function returns what we expect it to return.</p>



<figure class="wp-block-image"><img decoding="async" width="483" height="118" src="https://www.lucd.info/wp-content/uploads/2019/01/p1-1.jpg" alt="" class="wp-image-6273" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p1-1.jpg 483w, https://www.lucd.info/wp-content/uploads/2019/01/p1-1-300x73.jpg 300w" sizes="(max-width: 483px) 100vw, 483px" /></figure>



<p>In this test, which succeeded, we verified that our Do-Something function actually returned the text we expected.</p>



<p>If we test for another return value</p>



<pre class="wp-block-code"><code>function Do-Something {
    return "Doing something"
}

Describe 'Test doing something' -Tag 'OurTest' {
    It 'Function called' {
        Do-Something | Should -Be 'Not Doing something'
    }
}</code></pre>



<figure class="wp-block-image"><img decoding="async" width="497" height="242" src="https://www.lucd.info/wp-content/uploads/2019/01/p2-1.jpg" alt="" class="wp-image-6274" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p2-1.jpg 497w, https://www.lucd.info/wp-content/uploads/2019/01/p2-1-300x146.jpg 300w" sizes="(max-width: 497px) 100vw, 497px" /></figure>



<p>we get a failed test.</p>



<h3 class="wp-block-heading">Mocking</h3>



<p>In the previous examples we actually called our function. Executing the function did not do anything, it did not change anything in our environment. But not all functions or cmdlets are harmless like that.</p>



<p>For those types of functions and cmdlets we &#8220;mock&#8221; the real function/cmdlet.</p>



<pre class="wp-block-code"><code>function Do-Something{
    Write-Host "Doing something"
}

Describe 'Test doing something' -Tag 'OurTest' {
    Mock -CommandName Do-Something -MockWith {'Something else'}
    
    It 'Should run our mock' {
        Do-Something 

        Assert-MockCalled -CommandName Do-Something -Exactly 1
    }
}</code></pre>



<p>In this example we introduce two new Pester commands. The <a rel="noreferrer noopener" aria-label="Mock (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Mock" target="_blank">Mock</a> command and the <a rel="noreferrer noopener" aria-label="Assert-MockCalled (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Assert-MockCalled" target="_blank">Assert-MockCalled</a> command.</p>



<p>With the <strong>Mock</strong> command we &#8220;&#8230;  <br><em>specify a script block that will become the command&#8217;s new behavior</em> &#8220;. And  <strong>Assert-MockCalled</strong> &#8220;&#8230;  <br><em>verifies that a mocked command has been called a certain number of times</em>&#8220;.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="494" height="113" src="https://www.lucd.info/wp-content/uploads/2019/01/p3.jpg" alt="" class="wp-image-6275" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p3.jpg 494w, https://www.lucd.info/wp-content/uploads/2019/01/p3-300x69.jpg 300w" sizes="auto, (max-width: 494px) 100vw, 494px" /></figure>



<h3 class="wp-block-heading">Context</h3>



<p>We already saw the Describe block as a way of keeping related tests together, but we go one level deeper with the <a rel="noreferrer noopener" aria-label="Context (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Context" target="_blank">Context</a> command. It &#8221; <br><em>Provides logical grouping of&nbsp;</em><code><em>It</em></code><em>&nbsp;blocks within a single&nbsp;</em><code><em>Describe</em></code><em>&nbsp;block</em>&#8220;.</p>



<pre class="wp-block-code"><code>function Do-Something{
    Write-Host "Doing something"
}

Describe 'Test something else' -Tag 'OurTest' {
    Context 'Something else' {
        Mock -CommandName Do-Something -MockWith {'Something else'}
        
        It 'Should run our mock' {
            Do-Something 

            Assert-MockCalled -CommandName Do-Something -Exactly 1
        }

        It 'Should return "Something else"' {
            Do-Something | Should -Be 'Something else'
        }
    }

    Context 'Test something different' {
        Mock -CommandName Do-Something -MockWith {'Something different'}

        It 'Should not return "Something else"' {
            Do-Something | Should -Not -Be 'Something else'
        }

        It 'Should return "Something different"' {
            Do-Something | Should -Be 'Something different'
        }
    }
}</code></pre>



<p>Which results in</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="502" height="214" src="https://www.lucd.info/wp-content/uploads/2019/01/p4.jpg" alt="" class="wp-image-6276" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p4.jpg 502w, https://www.lucd.info/wp-content/uploads/2019/01/p4-300x128.jpg 300w" sizes="auto, (max-width: 502px) 100vw, 502px" /></figure>



<p>Notice how the test results follow the subdivision we created with our <strong>Describe</strong> and <strong>Context</strong> blocks.</p>



<h3 class="wp-block-heading">Tags</h3>



<p>A final feature I want to mention in this (very) basic Pester intro, is the concept of using Tags. On the Describe command, you can use the Tag parameter. These tags are a kind of label. When you run the Pester tests (with <a rel="noreferrer noopener" aria-label="Invoke-Pester (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Invoke-Pester" target="_blank">Invoke-Pester</a>), you can specify wich tests shall be executed by specifying tags.</p>



<pre class="wp-block-code"><code>function Do-Something{
    Write-Host "Doing something"
}

Describe 'Test something else' -Tag 'OurTest' {
    Mock -CommandName Do-Something -MockWith {'Something else'}
    
    It 'Should run our mock' {
        Do-Something 
    
        Assert-MockCalled -CommandName Do-Something -Exactly 1
    }
    
    It 'Should return "Something else"' {
        Do-Something | Should -Be 'Something else'
    }
}

Describe 'Test something different' -Tag 'HisTest' {
    Mock -CommandName Do-Something -MockWith {'Something different'}
    
    It 'Should not return "Something else"' {
        Do-Something | Should -Not -Be 'Something else'
    }
    
    It 'Should return "Something different"' {
        Do-Something | Should -Be 'Something different'
    }
}</code></pre>



<p>When we run this by just doing</p>



<p></p>



<pre class="wp-block-code"><code>Invoke-Pester -Script .\pcli-p5.Tests.ps1</code></pre>



<p>we get</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="479" height="185" src="https://www.lucd.info/wp-content/uploads/2019/01/p5.jpg" alt="" class="wp-image-6277" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p5.jpg 479w, https://www.lucd.info/wp-content/uploads/2019/01/p5-300x116.jpg 300w" sizes="auto, (max-width: 479px) 100vw, 479px" /></figure>



<p>but if we use the Tag parameter, we can do</p>



<pre class="wp-block-code"><code>Invoke-Pester -Script .\pcli-p5.Tests.ps1 -Tag 'OurTest'</code></pre>



<p>and that results in</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="490" height="126" src="https://www.lucd.info/wp-content/uploads/2019/01/p6.jpg" alt="" class="wp-image-6278" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p6.jpg 490w, https://www.lucd.info/wp-content/uploads/2019/01/p6-300x77.jpg 300w" sizes="auto, (max-width: 490px) 100vw, 490px" /></figure>



<h2 class="wp-block-heading">PowerCLI</h2>



<h3 class="wp-block-heading">Single Cmdlet</h3>



<p>As we already saw earlier, we can simulate the behaviour of cmdlets with the Mock command. Since we do not want any PowerCLI cmdlets we are using, to actually go out to a real vSphere environment, which might not even be there, we are going to use the <strong>Mock</strong> command.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    Get-VMHost
}

Describe 'PowerCLI Testing'{
    Mock -CommandName Get-VMHost -MockWith {}

    Do-PcliStuff

    It 'Should call VMHost' {
        Assert-MockCalled -CommandName Get-VMHost -Exactly 1
    }
}</code></pre>



<p>The function calls the PowerCLI cmdlet Get-VMHost and were mocking that cmdlet with an empty scriptblock. The result is similar to what we see earlier.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="486" height="114" src="https://www.lucd.info/wp-content/uploads/2019/01/p7.jpg" alt="" class="wp-image-6281" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p7.jpg 486w, https://www.lucd.info/wp-content/uploads/2019/01/p7-300x70.jpg 300w" sizes="auto, (max-width: 486px) 100vw, 486px" /></figure>



<p>But we probably also want to check if our code is passing the correct parameters to the Get-VMHost cmdlet. That is where the <strong>ParameterFilter</strong> on the <a rel="noreferrer noopener" aria-label="Mock (opens in a new tab)" href="https://github.com/pester/Pester/wiki/Mock" target="_blank">Mock</a> command comes into play. </p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name
}

$script:TestName = 'MyHost'

Describe 'PowerCLI Testing'{
    Mock -CommandName Get-VMHost -MockWith {} -ParameterFilter {$Name -eq $script:TestName}

    Do-PcliStuff -Name $script:TestName

    It 'Should call VMHost' {
        Assert-MockCalled -CommandName Get-VMHost -Exactly 1
    }
}</code></pre>



<p>Which results in</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="488" height="114" src="https://www.lucd.info/wp-content/uploads/2019/01/p8.jpg" alt="" class="wp-image-6282" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p8.jpg 488w, https://www.lucd.info/wp-content/uploads/2019/01/p8-300x70.jpg 300w" sizes="auto, (max-width: 488px) 100vw, 488px" /></figure>



<p>If we call the function with another value for the Name parameter, our test will fail.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name
}

$script:TestName = 'MyHost'

Describe 'PowerCLI Testing'{
    Mock -CommandName Get-VMHost -MockWith {} -ParameterFilter {$Name -eq $script:TestName}

    Do-PcliStuff -Name "$($script:TestName)_suffix"

    It 'Should call VMHost' {
        Assert-MockCalled -CommandName Get-VMHost -Exactly 1
    }
}</code></pre>



<p>which results in</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="188" src="https://www.lucd.info/wp-content/uploads/2019/01/p9-1024x188.jpg" alt="" class="wp-image-6283" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p9-1024x188.jpg 1024w, https://www.lucd.info/wp-content/uploads/2019/01/p9-300x55.jpg 300w, https://www.lucd.info/wp-content/uploads/2019/01/p9-768x141.jpg 768w, https://www.lucd.info/wp-content/uploads/2019/01/p9-720x132.jpg 720w, https://www.lucd.info/wp-content/uploads/2019/01/p9.jpg 1152w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>What we are seeing here is interesting to further analyse. Our mock for Get-VMHost was not taken due to the ParameterFilter we used. So that is working as desired.</p>



<p>But as a consequence, the test now used the &#8220;real&#8221; Get-VMHost, which we can see by the fact that the cmdlet complains there is no  connection.</p>



<p>One way of avoiding that  is by creating a kind of catch-all Mock.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name
}

$script:TestName = 'MyHost'

Describe 'PowerCLI Testing'{
    Mock -CommandName Get-VMHost -MockWith {return "All is well"} -ParameterFilter {$Name -eq $script:TestName}

    Mock -CommandName Get-VMHost -MockWith {return "Catch-all"}

    $result = Do-PcliStuff -Name "$($script:TestName)_suffix"

    It 'Should call VMHost' {
        Assert-MockCalled -CommandName Get-VMHost -Exactly 1
    }

    It 'Desired mock taken' {
        $result | Should -Be "All is well"
    }
}</code></pre>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="514" height="254" src="https://www.lucd.info/wp-content/uploads/2019/01/p10.jpg" alt="" class="wp-image-6284" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p10.jpg 514w, https://www.lucd.info/wp-content/uploads/2019/01/p10-300x148.jpg 300w" sizes="auto, (max-width: 514px) 100vw, 514px" /></figure>



<p>We do get a failed test, but at least our testing is not calling the real cmdlet anymore.</p>



<h3 class="wp-block-heading">Cmdlets in a Pipeline</h3>



<p>We often use the pipeline to link two cmdlets together. Testing such a construct only requires adding additional mocks.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name | Get-VM
}

$script:TestName = 'MyHost'

Describe 'PowerCLI Testing'{
    Mock -CommandName Get-VMHost -MockWith {} -ParameterFilter {$Name -eq $script:TestName}
    Mock -CommandName Get-VM -MockWith {}

    $result = Do-PcliStuff -Name $script:TestName

    It 'Should call Get-VMHost' {
        Assert-MockCalled -CommandName Get-VMHost -Exactly 1
    }

    It 'Should call Get-VM' {
        Assert-MockCalled -CommandName Get-VM -Exactly 1
    }
}</code></pre>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="476" height="130" src="https://www.lucd.info/wp-content/uploads/2019/01/p11.jpg" alt="" class="wp-image-6286" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p11.jpg 476w, https://www.lucd.info/wp-content/uploads/2019/01/p11-300x82.jpg 300w" sizes="auto, (max-width: 476px) 100vw, 476px" /></figure>



<p>That was easy.</p>



<h3 class="wp-block-heading">Mocking the Module</h3>



<p>But what if there are conditions on properties. For example a Where-clause, in the pipeline construct that tests if a VMHost has four or less CPUs? How do we test if our code is handling that correctly in all possible scenarios.</p>



<pre class="wp-block-code"><code>Get-VMHost -Name $Name | where{$_.NumCpu -le 4} | Get-VM</code></pre>



<p>We need to be able to mock the output of the Get-VMHost cmdlet. Unfortunately, the way PowerCLI types are currently set up, we can not just create new PowerCLI objects and assign values to their properties. In fact there is a <a rel="noreferrer noopener" aria-label="PowerCLI Idea (opens in a new tab)" href="https://powercli.ideas.aha.io/ideas/PCLI-I-103" target="_blank">PowerCLI Idea</a> open to change that behaviour.</p>



<p>The solution that DSCR has chosen is to create a mock module <strong>VMware.VimAutomation.Core</strong>. This is the module where most PowerCLI types are defined. <br></p>



<p>If we replace that module with our own module, we can completely manipulate PowerCLI objects. And we can make sure that our Pester tests use that module, by explicitly importing it in our test script.</p>



<p>For the test scripts in this post I used a very simple setup.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="507" height="261" src="https://www.lucd.info/wp-content/uploads/2019/01/tree.jpg" alt="" class="wp-image-6291" srcset="https://www.lucd.info/wp-content/uploads/2019/01/tree.jpg 507w, https://www.lucd.info/wp-content/uploads/2019/01/tree-300x154.jpg 300w" sizes="auto, (max-width: 507px) 100vw, 507px" /></figure>



<p>In the mock module <strong>VMware.VimAutomation.Core</strong> we have the following content.</p>



<pre class="wp-block-code"><code>Add-Type -TypeDefinition @"
 namespace VMware.Vim
 {
    public class VMHost
    {
        // Property used only for comparing VMHost objects.
        public string Id { get; set; }

        public string Name { get; set; }

        public int NumCpu { get; set; }

    }
  }
"@

function Get-VMHost {
    param(
        [PSObject] $Server,
        [string] $Name
    )

    return New-Object VMware.Vim.VMHost
}

function Get-VM {
    param(
        [PSObject] $Server,
        [string]$Name,
        [parameter(ValueFromPipeline)]
        [PSObject] $Location
    )

    return $null
}</code></pre>



<h4 class="wp-block-heading">Annotations</h4>



<table id="tablepress-1" class="tablepress tablepress-id-1">
<thead>
<tr class="row-1">
	<th class="column-1">Line</th><th class="column-2">Annotation</th>
</tr>
</thead>
<tbody>
<tr class="row-2">
	<td class="column-1">1-15</td><td class="column-2">Use the Add-Type cmdlet to create the class VMware.Vim.VMHost with the properties we require, i.e. NumCpu</td>
</tr>
<tr class="row-3">
	<td class="column-1">2</td><td class="column-2">All classes are defined in the VMware.Vim namespace</td>
</tr>
<tr class="row-4">
	<td class="column-1">17-24</td><td class="column-2">Define our version of the Get-VMHost cmdlet</td>
</tr>
<tr class="row-5">
	<td class="column-1"> 26-35</td><td class="column-2">Define our version of the Get-VM cmdlet</td>
</tr>
<tr class="row-6">
	<td class="column-1">30-31</td><td class="column-2">Define the Location parameter to accept pipeline values of type PSObject.</td>
</tr>
</tbody>
</table>
<!-- #tablepress-1 from cache -->



<p>Our test script now imports our mock module. This allows us to specify exactly what the <strong>Get-VMHost</strong> cmdlet is going to return via a <strong>hashtable</strong> that we use the define the <strong>content of the object</strong> that is returned by our Get-VMHost mock.</p>



<p>And since we defined what kind of parameter our <strong>Get-VM</strong> cmdlet accepts over the pipeline, we can combine our cmdlets in a pipeline construct.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name | 
    where{$_.NumCpu -le 4} | 
    Get-VM
}

$script:TestName = 'MyHost'

Import-Module -Name .\VMware.VimAutomation.Core -Verbose

Describe 'PowerCLI Testing'{
    $vmHostMock = {
        return [VMware.Vim.VMHost] @{
            Id = 'VMHostId'
            Name = 'esx1'
            NumCpu = 4
        }
    }

    Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
    Mock -CommandName Get-VM -MockWith {}

    $result = Do-PcliStuff -Name $script:TestName

    It 'Should call Get-VMHost' {
        Assert-MockCalled -CommandName Get-VMHost -Exactly 1
    }

    It 'Should call Get-VM' {
        Assert-MockCalled -CommandName Get-VM -Exactly 1
    }
}</code></pre>



<p>The results in</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="794" height="213" src="https://www.lucd.info/wp-content/uploads/2019/01/p12.jpg" alt="" class="wp-image-6305" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p12.jpg 794w, https://www.lucd.info/wp-content/uploads/2019/01/p12-300x80.jpg 300w, https://www.lucd.info/wp-content/uploads/2019/01/p12-768x206.jpg 768w, https://www.lucd.info/wp-content/uploads/2019/01/p12-720x193.jpg 720w" sizes="auto, (max-width: 794px) 100vw, 794px" /></figure>



<p>Notice how I used the <strong>Verbose</strong> switch to show where our mock module is coming from.</p>



<p>Now that we have the pipeline construct working we can add test cases for multiple possibilities.</p>



<p>This is a good moment to introduce different Context blocks for different test cases. We will do one context for an ESXi node with 4 CPU and another context for an ESXi node with 8 CPU.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name | 
    where{$_.NumCpu -le 4} | 
    Get-VM
}

$script:TestName = 'MyHost'

Import-Module -Name .\VMware.VimAutomation.Core

Describe 'PowerCLI Testing' {
    Context 'ESXi node with 4 CPU' {
        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'esx1'
                NumCpu = 4
            }
        }

        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
        Mock -CommandName Get-VM -MockWith {} -ParameterFilter {$Location.Name -eq 'esx1'}
    
        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }
    
        It 'Should call Get-VM' {
            Assert-MockCalled -CommandName Get-VM -Exactly 1
        }
    }

    Context 'ESXi node with 8 CPU' {
        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'esx1'
                NumCpu = 8
            }
        }
    
        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
        Mock -CommandName Get-VM -MockWith {}
    
        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }
    
        It 'Should not call Get-VM' {
            Assert-MockCalled -CommandName Get-VM -Exactly 0
        }
    }
}</code></pre>



<p>Notice how have test for zero calls to Get-VM in the second context. Due to the Where-clause that VMHost object should not get through. The result</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="489" height="209" src="https://www.lucd.info/wp-content/uploads/2019/01/p13.jpg" alt="" class="wp-image-6306" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p13.jpg 489w, https://www.lucd.info/wp-content/uploads/2019/01/p13-300x128.jpg 300w" sizes="auto, (max-width: 489px) 100vw, 489px" /></figure>



<p>If you look at the ParameterFilter on the Get-VM mock in the first context block, you will notice that we test a specific property of the VMHost object. Would it not be better to be able to test on the complete VMHost object?</p>



<p>Of course it would, but for that we need to adapt our VMHost class in our mock module. We need to add the <a href="https://docs.microsoft.com/en-us/dotnet/api/system.iequatable-1?view=netframework-4.7.2" target="_blank" rel="noreferrer noopener" aria-label="IEquatable interface (opens in a new tab)">IEquatable interface</a> to the class. That adds to our class the ability to determine if two instances of the class are identical.</p>



<pre class="wp-block-code"><code>Add-Type -TypeDefinition @"
 namespace VMware.Vim
 {
    public class VMHost : System.IEquatable<VMHost>
    {
        // Property used only for comparing VMHost objects.
        public string Id { get; set; }

        public string Name { get; set; }

        public int NumCpu { get; set; }

        public bool Equals(VMHost vmhost)
        {
            return vmhost != null && this.Id == vmhost.Id && this.Name == vmhost.Name;
        }

        public override bool Equals(object vmhost)
        {
            return this.Equals(vmhost as VMHost);
        }

        public override int GetHashCode()
        {
            return (this.Id + "_" + this.Name + "_" + this.NumCpu).GetHashCode();
        }
    }
  }
"@

function Get-VMHost {
    param(
        [PSObject] $Server,
        [string] $Name
    )

    return New-Object VMware.Vim.VMHost
}

function Get-VM {
    param(
        [PSObject] $Server,
        [string]$Name,
        [parameter(ValueFromPipeline)]
        [PSObject] $Location
    )

    return $null
}</code></pre>



<p>And we can adapt the <strong>ParameterFilter</strong>.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    Get-VMHost -Name $Name | 
    where{$_.NumCpu -le 4} | 
    Get-VM
}

$script:TestName = 'MyHost'

Import-Module -Name .\VMware.VimAutomation.Core

Describe 'PowerCLI Testing' {
    Context 'ESXi node with 4 CPU' {
        $vmHost = [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'esx1'
                NumCpu = 4
        }

        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'esx1'
                NumCpu = 4
            }
        }

        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
        Mock -CommandName Get-VM -MockWith {} -ParameterFilter {$Location  -eq $vmHost}
    
        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }
    
        It 'Should call Get-VM' {
            Assert-MockCalled -CommandName Get-VM -Exactly 1
        }
    }
    Context 'ESXi node with 2 CPU' {
        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'esx1'
                NumCpu = 2
            }
        }
    
        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
        Mock -CommandName Get-VM -MockWith {} -ParameterFilter {$Location -eq $null}
    
        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }
    
        It 'Should call Get-VM' {
            Assert-MockCalled -CommandName Get-VM -Exactly 0
        }
    }
}</code></pre>



<p>The result of a run looks the same, with the difference that we now compared the complete <strong>VMHost object</strong>.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="495" height="213" src="https://www.lucd.info/wp-content/uploads/2019/01/p14.jpg" alt="" class="wp-image-6307" srcset="https://www.lucd.info/wp-content/uploads/2019/01/p14.jpg 495w, https://www.lucd.info/wp-content/uploads/2019/01/p14-300x129.jpg 300w" sizes="auto, (max-width: 495px) 100vw, 495px" /></figure>



<h2 class="wp-block-heading">vSphere</h2>



<h3 class="wp-block-heading">Get-View and ExtensionData</h3>



<p>We all know that sometimes we have go into the <a rel="noreferrer noopener" aria-label="vSphere API (opens in a new tab)" href="https://code.vmware.com/apis/358/vsphere" target="_blank">vSphere API</a> to retieve  properties or to call methods that are not exposed directly through any of the PowerCLI cmdlets.</p>



<p> The code behind DSCR is no different. But how will we test access to these vSphere API properties or calls to any of the vSphere API methods?</p>



<p>Turns out that this is not very different from what we already did for the PowerCLI cmdlets. We define the vSphere API objects in our <strong>mock module</strong>. And we can <strong>mock</strong> the <strong>Get-View</strong> cmdlet and the<strong> ExtensionData</strong> property.</p>



<p>In the following example we have code that looks at the current EVCMode ofan ESXi node, and then returns that mode in a more human readable format. Nothing too fancy.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    $esx = Get-VMHost -Name $Name
    switch($esx.ExtensionData.Summary.CurrentEVCModeKey)
    {
    'intel-merom' {'Intel® “Merom” Generation'}
    'intel-penryn' {'Intel® “Penryn” Generation'}
    'intel-nehalem' {'Intel® “Nehalem” Generation'}
    'intel-westmere' {'Intel® “Westmere” Generation'}
    'intel-sandybridge' {'Intel® “Sandy Bridge” Generation'}
    'intel-ivybridge' {'Intel® “Ivy Bridge” Generation'}
    }
}</code></pre>



<p>Since we are fetching values under ExtensionData we will have to define the required classes and properties in our mock module. We add the HostExtensionData and HostListSummary classes to our module mock.</p>



<p>Note that we only added the properties that are required for this test case. When more test cases are created, the class definitions will be expanded.</p>



<pre class="wp-block-code"><code>Add-Type -TypeDefinition @"
 namespace VMware.Vim
 {
    public class HostListSummary
    {
        public string CurrentEVCModeKey { get; set; }
    }

    public class HostExtensionData
    {
        public HostListSummary Summary { get; set; }
    }

    public class VMHost : System.IEquatable&lt;VMHost>
    {
        // Property used only for comparing VMHost objects.
        public string Id { get; set; }

        public string Name { get; set; }

        public int NumCpu { get; set; }

        public HostExtensionData ExtensionData { get; set; }

        public bool Equals(VMHost vmhost)
        {
            return vmhost != null &amp;&amp; this.Id == vmhost.Id &amp;&amp; this.Name == vmhost.Name;
        }

        public override bool Equals(object vmhost)
        {
            return this.Equals(vmhost as VMHost);
        }

        public override int GetHashCode()
        {
            return (this.Id + "_" + this.Name + "_" + this.NumCpu).GetHashCode();
        }
    }
  }
"@</code></pre>



<p>Our test script looks like this.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    $esx = Get-VMHost -Name $Name
    switch($esx.ExtensionData.Summary.CurrentEVCModeKey)
    {
    'intel-merom' {'Intel® “Merom” Generation'}
    'intel-penryn' {'Intel® “Penryn” Generation'}
    'intel-nehalem' {'Intel® “Nehalem” Generation'}
    'intel-westmere' {'Intel® “Westmere” Generation'}
    'intel-sandybridge' {'Intel® “Sandy Bridge” Generation'}
    'intel-ivybridge' {'Intel® “Ivy Bridge” Generation'}
    }
}

$script:TestName = 'MyHost'

Import-Module -Name .\VMware.VimAutomation.Core

Describe 'PowerCLI Testing' {
    Context 'EVC mode retrieval' {
        $vmHost = [VMware.Vim.VMHost] @{
            Id = 'VMHostId'
            Name = 'MyHost'
            NumCpu = 4
        }

        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'MyHost'
                ExtensionData = [VMware.Vim.HostExtensionData] @{
                    Summary = [VMware.Vim.HostListSummary] @{
                        CurrentEVCModeKey = 'intel-merom'
                    }
                }
            }
        }

        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
    
        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }
    
        It 'Should return the expected value' {
            $result | Should -Be 'Intel® “Merom” Generation'
        }
    }
}</code></pre>



<p>And all our tests pass.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="484" height="156" src="https://www.lucd.info/wp-content/uploads/2019/02/p15.jpg" alt="" class="wp-image-6321" srcset="https://www.lucd.info/wp-content/uploads/2019/02/p15.jpg 484w, https://www.lucd.info/wp-content/uploads/2019/02/p15-300x97.jpg 300w" sizes="auto, (max-width: 484px) 100vw, 484px" /></figure>



<p>But what when we want test a call to an API method?</p>



<p>Again, the trick is in defining the required method in the class definition in the mock module. In this case we a method, named <strong>RetrieveHardwareUptime</strong> , to the HostExtensionData class. For this particular test we are not interested in the actual value that is returned, just in the type.</p>



<pre class="wp-block-code"><code>Add-Type -TypeDefinition @"
 namespace VMware.Vim
 {
    public class HostListSummary
    {
        public string CurrentEVCModeKey { get; set; }
    }

    public class HostExtensionData
    {
        public HostListSummary Summary { get; set; }

        public long RetrieveHardwareUptime() {
            long result = 1;

            return result;
        }
    }

    public class VMHost : System.IEquatable&lt;VMHost>
    {
        // Property used only for comparing VMHost objects.
        public string Id { get; set; }

        public string Name { get; set; }

        public int NumCpu { get; set; }

        public HostExtensionData ExtensionData { get; set; }

        public bool Equals(VMHost vmhost)
        {
            return vmhost != null &amp;&amp; this.Id == vmhost.Id &amp;&amp; this.Name == vmhost.Name;
        }

        public override bool Equals(object vmhost)
        {
            return this.Equals(vmhost as VMHost);
        }

        public override int GetHashCode()
        {
            return (this.Id + "_" + this.Name + "_" + this.NumCpu).GetHashCode();
        }
    }
  }
"@</code></pre>



<p>With the method in place, we can now write our test script. Note that we test the returned (and hard coded) value and the type.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    $esx = Get-VMHost -Name $Name
    $esx.ExtensionData.RetrieveHardwareUptime()
}

$script:TestName = 'MyHost'

Import-Module -Name .\VMware.VimAutomation.Core

Describe 'PowerCLI Testing' {
    Context 'Hardware Uptime' {
        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'MyHost'
                ExtensionData = [VMware.Vim.HostExtensionData] @{}
            }
        }

        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
    
        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }

        It 'Should return the expected type' {
            $result | Should -BeOfType [long]
        }
    
        It 'Should return the expected value' {
            $result | Should -Be 1
        }
    }
}</code></pre>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="483" height="173" src="https://www.lucd.info/wp-content/uploads/2019/02/p16.jpg" alt="" class="wp-image-6323" srcset="https://www.lucd.info/wp-content/uploads/2019/02/p16.jpg 483w, https://www.lucd.info/wp-content/uploads/2019/02/p16-300x107.jpg 300w" sizes="auto, (max-width: 483px) 100vw, 483px" /></figure>



<p>Note that in the current Pester version it is <strong>not possible</strong> to test<strong> object methods</strong>. In other words we can not test, at this point in time, if the RetrieveHardwareUptime method is called.</p>



<h3 class="wp-block-heading">Esxcli</h3>



<p>For some properties and for some methods a call of the esxcli command is sometimes the only available or fastest method. In PowerCLI we have the Get-EsxCli cmdlet that allows us to do these calls. But how do we Pester test such calls?</p>



<p>Turns out we can mock the complete <strong>esxcli</strong> object.</p>



<pre class="wp-block-code"><code>function Do-PCLIStuff{
    param(
        [string]$Name
    )

    $esx = Get-VMHost -Name $Name
    $esxcli = Get-EsxCli -VMHost $esx -V2
    $esxcli.system.time.get.Invoke()
}

$script:TestName = 'MyHost'

Import-Module -Name .\VMware.VimAutomation.Core

Describe 'PowerCLI Testing' {
    Context 'Get time' {
        $vmhostObject = [VMware.Vim.VMHost] @{ 
            Id = 'VMHostId'
            Name = 'MyHost'
        }

        $timeString = (Get-Date '01/01/2019 00:00').ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.000Z')

        $vmHostMock = {
            return [VMware.Vim.VMHost] @{
                Id = 'VMHostId'
                Name = 'MyHost'
            }
        }

        $esxCliMock = {
            $esxcli = New-Object PSObject
            $esxcli | Add-Member -MemberType NoteProperty -Name 'id' -Value 'esxCli Id'
            $esxcli | Add-Member -MemberType NoteProperty -Name 'system' -Value (New-Object PSObject)
            $esxcli.system | Add-Member -MemberType NoteProperty -Name 'time' -Value (New-Object PSObject)
            $esxcli.system.time | Add-Member -MemberType NoteProperty -Name 'get' -Value (New-Object PSObject)

            $esxcli.system.time.get | Add-Member -MemberType ScriptMethod -Name 'Invoke' -Value { $timeString }
            
            return $esxcli
        }

        Mock -CommandName Get-VMHost -MockWith $vmHostMock -ParameterFilter {$Name -eq $script:TestName}
        Mock -CommandName Get-EsxCli -MockWith $esxcliMock -ParameterFilter {$VMHost -eq $vmhostObject}

        $result = Do-PcliStuff -Name $script:TestName
    
        It 'Should call Get-VMHost' {
            Assert-MockCalled -CommandName Get-VMHost -Exactly 1
        }

        It 'Should call Get-EsxCli' {
            Assert-MockCalled -CommandName Get-EsxCli -Exactly 1
        }

        It 'Should return the expected value' {
            $result | Should -Be $timeString
        }
    }
}</code></pre>



<p>We construct the $esxCliMock code block in such a way that it will return an object, with an Invoke() method, via the ScriptMethod type, that returns the value.</p>



<p>For the test script we will also have to create a definition for the Get-EsxCli cmdlet in our mock module. The purpose is to have a declaration of the required parameters for the Get-EsxCli cmdlet. Remember that we are replacing the regular PowerCLI module that contains the Get-EsxCli cmdlet, with our mock module.</p>



<pre class="wp-block-code"><code>function Get-EsxCli {
    param(
        [PSObject] $Server,
        [VMware.Vim.VMHost] $VMHost,
        [switch] $V2
    )

    return $null
}</code></pre>



<p>And this results in</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="475" height="172" src="https://www.lucd.info/wp-content/uploads/2019/02/p17.jpg" alt="" class="wp-image-6326" srcset="https://www.lucd.info/wp-content/uploads/2019/02/p17.jpg 475w, https://www.lucd.info/wp-content/uploads/2019/02/p17-300x109.jpg 300w" sizes="auto, (max-width: 475px) 100vw, 475px" /></figure>



<h2 class="wp-block-heading">Conclusion</h2>



<p>Writing Pester Unit tests for code that uses VMware PowerCLI and that works against a vSphere environment, is not intuitive at all at first sight.</p>



<p>One has to take into account the many peculiarities that exist. And more importantly, one has to reflect on how one can &#8220;mock&#8221; all the techniques you normally use in your VMware PowerCLI code.</p>



<p>I hope this short overview of some techniques will encourage you to start writing Pester tests, not only for DSCR, but also for your own scripts. In the end, having testing in place will help you a lot when you need to change/update your code.</p>



<p>I encourage you all to share your Pester tests for PowerCLI scripts. And I welcome all suggestions for additions or updates to this post.</p>



<p>Enjoy!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.lucd.info/2019/02/01/dscr-and-pester-testing/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
	</channel>
</rss>
