2

i am new to pester testing and i a am curently trying to test a custom dsc resource i have made, the function i am testing is the following:

<#
    .SYNOPSIS
        Get parameters for Snmp configuration

    .PARAMETER AgentSvcPhysical
        Used as a boolean flag to set (True) or unset (False) the Physical 
checkbox (Agent Tab, Service section)

    .PARAMETER AgentSvcApplications
        Used as a boolean flag to set (True) or unset (False) the 
Applications checkbox (Agent Tab, Service section)

    .PARAMETER AgentSvcDatalink
        Used as a boolean flag to set (True) or unset (False) the Datalink 
and subnetwork checkbox (Agent Tab, Service section)

    .PARAMETER AgentSvcInternet
        Used as a boolean flag to set (True) or unset (False) the Internet 
checkbox (Agent Tab, Service section)

    .PARAMETER AgentSvcEnd2End
        Used as a boolean flag to set (True) or unset (False) the End-To-End 
checkbox (Agent Tab, Service section)

    .PARAMETER AgentContact
        Used as a string to set (or unset) the name of the contact for SNMP, 
leave blank to unset

    .PARAMETER AgentLocation
        Used as a string to set (or unset) the location for SNMP, leave 
blank to unset

    .PARAMETER SecSendTraps
        Used as a boolean flag to set (True) or unset (False) the Send 
authentication trap checkbox (Security Tab)

    .PARAMETER SecCommName
        Used as a string to set (or unset) the community name, leave blank 
to remove

    .PARAMETER SecCommRights
        Used as a string to set (or unset) the community rights, USAGE: 
"NONE", "NOTIFY", "READ ONLY", "READ WRITE" or "READ CREATE" 

    .PARAMETER SecAuthPackets
        Used as a boolean flag to set (True) or unset (False) the value for 
snmp packet acceptance (Security Tab). USAGE: True= "Accept packet from any 
host", False="Accept packet from these hosts" (if set to false you need to 
specify a value for the SecPacketsHost parameter)

    .PARAMETER SecPacketsHost
        Used as a string to set (or unset) the authorized hostname to send 
SNMP packet to the host (can be a hostame or ip address), if you need to 
enter more than one host use ; as separator. Ex:
10.0.0.1;10.0.0.2
#> function Get-TargetResource {
    [CmdletBinding()]
    [OutputType([Hashtable])]
    param
    (
        [Parameter(Mandatory = $false)]
        [ValidateSet("Present", "Absent")]
        [string]$Ensure = "Absent",

        [Parameter(Mandatory = $false)]
        [bool]
        $AgentSvcPhysical = $false,

        [Parameter(Mandatory = $false)]
        [bool]
        $AgentSvcApplications = $false,

        [Parameter(Mandatory = $false)]
        [bool]
        $AgentSvcDatalink = $false,

        [Parameter(Mandatory = $false)]
        [bool]
        $AgentSvcInternet = $false,

        [Parameter(Mandatory = $false)]
        [bool]
        $AgentSvcEnd2End = $false,

        [Parameter(Mandatory = $false)]
        [ValidateNotNull()]
        [String]
        [AllowEmptyString()]
        $AgentContact = "",

        [Parameter(Mandatory = $false)]
        [ValidateNotNull()]
        [String]
        [AllowEmptyString()]
        $AgentLocation = "",

        [Parameter(Mandatory = $false)]
        [bool]
        $SecSendTraps = $false,

        [Parameter(Mandatory = $true)]
        [ValidateNotNull()]
        [String]
        [AllowEmptyString()]
        $SecCommName = "",

        [Parameter(Mandatory = $false)]
        [ValidateSet('NONE', 'NOTIFY', 'READ ONLY', 'READ WRITE', 'READ CREATE')]
        [String]
        $SecCommRights = "NONE",

        [Parameter(Mandatory = $false)]
        [bool]
        $SecAuthPackets = $false,

        [Parameter(Mandatory = $false)]
        [String]
        $SecPacketsHost = "NotSet"

    )
    # Default values before runnning resource logic
    $snmpResource = @{
        SecCommName = $SecCommName
        Ensure = 'Absent'
        AgentSvcPhysical = $false
        AgentSvcApplications = $false
        AgentSvcDatalink = $false
        AgentSvcInternet = $false
        AgentSvcEnd2End = $false
        AgentContact = $AgentContact
        AgentLocation = $AgentLocation
        SecSendTraps = $false
        SecCommRights = $SecCommRights
        SecAuthPackets = $false
        SecPacketsHost = $SecPacketsHost
    }

    #key parameter to validate state
    $SecComm_Key = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities"

    #Assigning values from user input  if ($AgentSvcPhysical -eq $true) {
    Write-Verbose -Message "AgentSvcPhysical value set to true"
    $snmpResource['AgentSvcPhysical'] = $true  }    if ($AgentSvcApplications -eq $true) {
    Write-Verbose -Message "AgentSvcApplications value set to true"
    $snmpResource['AgentSvcApplications'] = $true }

if ($AgentSvcDatalink -eq $true) {
    Write-Verbose -Message "AgentSvcDatalink value set to true"
    $snmpResource['AgentSvcDatalink'] = $true }

if ($AgentSvcInternet -eq $true) {
    Write-Verbose -Message "AgentSvcInternet value set to true"
    $snmpResource['AgentSvcInternet'] = $true }

if ($AgentSvcEnd2End -eq $true) {
    Write-Verbose -Message "AgentSvcEnd2End value set to true"
    $snmpResource['AgentSvcEnd2End'] = $true }

if ($SecSendTraps -eq $true) {
    Write-Verbose -Message "SecSendTraps value set to true"
    $snmpResource['SecSendTraps'] = $true } if ($SecAuthPackets -eq $true) {
    Write-Verbose -Message "SecAuthPackets value set to true"
    $snmpResource['SecAuthPackets'] = $true } $valueNameSpecified= (-not [String]::IsNullOrEmpty($SecCommName)) if ($valueNameSpecified
-eq $true) {
    $registryKey= Get-RegistryKey_HF -RegistryKeyPath $SecComm_Key -WriteAccessAllowed
    if ($null -eq $registryKey) {
        Write-Verbose -Message "Registry Key Does Not Exist"
    }
    else {
        Write-Verbose -Message "Registry Key Exist"
        $valueDisplayName = Get-RegistryKeyValueDisplayName_HF -RegistryKeyValueName $SecCommName
        $snmpResource['SecCommName'] = $valueDisplayName
        $registryKeyValue = Get-RegistryKeyValue_HF -RegistryKey $registryKey -RegistryKeyValueName $valueDisplayName
        if ($null -eq $RegistryKeyValue) {
            Write-Verbose -Message "Registry Key Value Does Not Exist"
        }
        else {
            Write-Verbose -Message "Registry Key Value Does Exist"
            #we determine the community security from user input
            switch ($SecCommRights) {
                "NONE" { $desiredValue = 1 }
                "NOTIFY" { $desiredValue = 2 }
                "READ ONLY" { $desiredValue = 4 }
                "READ WRITE" { $desiredValue = 8 }
                "READ CREATE" { $desiredValue = 16 }

            }

            $keyValuesMatch= Test-RegistryKeyValuesMatch_HF -ExpectedRegistryKeyValue $desiredValue -ActualRegistryKeyValue $registryKeyValue -RegistryKeyValueType 'DWord'
            if ($keyValuesMatch -eq $true) {
                Write-Verbose -Message "The registry key value match user input, state = Present"
                $snmpResource['Ensure'] = 'Present'
            }
        }
    } }

return $snmpResource }

When i test the resource manually without pester, it returns the correct result as on this image: get-targetresource result

Here are my pester code for testing:

<#
    .SYNOPSIS
        Snmp_Dsc Unit testing script
    .DESCRIPTION
        To Use:
        1. Copy to \Tests\Unit\ folder and rename <ResourceName>.tests.ps1 (e.g. MSFT_xFirewall.tests.ps1)
        2. Customize TODO sections.
        3. Delete all template comments (TODOs, etc.)

    .NOTES
        There are multiple methods for writing unit tests. This template provides a few examples
        which you are welcome to follow but depending on your resource, you may want to
        design it differently. Read through our TestsGuidelines.md file for an intro on how to
        write unit tests for DSC resources: https://github.com/PowerShell/DscResources/blob/master/TestsGuidelines.md
#>

#region HEADER

# Unit Test Template Version: 1.2.1

#Path to the ..\Tests folder
$script:testFolderPath = Split-Path -Path $PSScriptRoot -Parent
#Path to the ..\Tests\TestHelpers folder
$script:testHelpersPath = Join-Path -Path $script:testFolderPath -ChildPath 'TestHelpers'

$moduleRootFilePath = Split-Path -Path $script:testFolderPath -Parent
$snmpResourceModuleFilePath = Join-Path -Path $moduleRootFilePath -ChildPath 'Snmp_Dsc.psm1'


#We import the CommonTestHelper.psm1 module from the ..\Tests\TestHelpers folder
Import-Module -Name (Join-Path -Path $script:testHelpersPath -ChildPath 'CommonTestHelper.psm1')
#We import the MSFT_RegistryResource.TestHelper.psm1 module from the ..\Tests\TestHelpers folder
Import-Module -Name (Join-Path -Path $script:testHelpersPath -ChildPath 'MSFT_RegistryResource.TestHelper.psm1')
#We import the MSFT_ServiceResource.TestHelper.psm1 module from the ..\Tests\TestHelpers folder
Import-Module -Name (Join-Path -Path $script:testHelpersPath -ChildPath 'MSFT_ServiceResource.TestHelper.psm1')

# TODO: Insert the correct <ModuleName> and <ResourceName> for your resource


#endregion HEADER

function Invoke-TestSetup {
    # TODO: Optional init code goes here...
}

function Invoke-TestCleanup {
    Restore-TestEnvironment -TestEnvironment $TestEnvironment

    # TODO: Other Optional Cleanup Code Goes Here...
}

# Begin Testing
try
{
    Invoke-TestSetup

        $script:registryKeyValueTypes = @( 'String', 'Binary', 'DWord', 'QWord', 'MultiString', 'ExpandString' )
        $script:validRegistryDriveRoots = @( 'HKEY_CLASSES_ROOT', 'HKEY_CURRENT_USER', 'HKEY_LOCAL_MACHINE', 'HKEY_USERS', 'HKEY_CURRENT_CONFIG' )
        $script:validRegistryDriveNames = @( 'HKCR', 'HKCU', 'HKLM', 'HKUS', 'HKCC' )
        #Values for testing
        $script:SecComm_Key = "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities"
        $script:SecComm_KeyValue = "4"
        $script:SecComm_KeyType = 'DWord'
        # This registry key is used ONLY for its type (Microsoft.Win32.RegistryKey). It is not actually accessed in any way during these tests.
        $script:testRegistryKey = [Microsoft.Win32.Registry]::CurrentConfig
        Describe 'Snmp\Get-TargetResource' {
            Copy-Item $snmpResourceModuleFilePath TestDrive:\Snmp_Dsc.ps1 -Force
            Mock Export-ModuleMember {return $true}
            . "TestDrive:\Snmp_Dsc.ps1"
            Mock -CommandName 'Get-RegistryKey_HF' -MockWith { }

            Context 'Key parameter (SecCommName) is set to public and SecCommRight is set to NONE' {
                BeforeEach {
                    $path = "HKLM:\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities"
                    Remove-ItemProperty –Path $path –Name "public" -ErrorAction SilentlyContinue -Force 
                    New-ItemProperty -Path $path -Name "public" -Value 1 -PropertyType "DWORD" -ErrorAction SilentlyContinue 
                }

                $getTargetResourceParameters = @{
                    AgentSvcPhysical = $true
                    AgentSvcApplications = $true
                    AgentSvcDatalink = $true
                    AgentSvcInternet = $true
                    AgentSvcEnd2End = $true
                    SecSendTraps = $true
                    SecCommName = "public"
                    SecCommRights = "NONE"
                    SecAuthPackets = $true
                }

                It 'Should not throw' {
                    { $null = Get-TargetResource @getTargetResourceParameters } | Should Not Throw
                }

                It 'Should retrieve the registry key' {
                    $getRegistryKeyParameterFilter = {
                        $registryKeyPathParameterCorrect = $RegistryKeyPath -eq $script:SecComm_Key
                        return $registryKeyPathParameterCorrect
                    }

                    Assert-MockCalled -CommandName 'Get-RegistryKey_HF' -ParameterFilter $getRegistryKeyParameterFilter -Times 1 -Scope 'Context'
                }

                $getTargetResourceResult = Get-TargetResource @getTargetResourceParameters

                It 'Should return a hashtable' {
                    $getTargetResourceResult -is [Hashtable] | Should Be $true
                }

                It 'Should return 13 hashtable properties' {
                    $getTargetResourceResult.Keys.Count | Should Be 13
                }

                It 'Should return the AgentSvcPhysical property as True' {
                    $getTargetResourceResult.AgentSvcPhysical | Should Be $true
                }

                It 'Should return the AgentSvcApplications property as True' {
                    $getTargetResourceResult.AgentSvcApplications | Should Be $true
                }

                It 'Should return the AgentSvcDatalink property as True' {
                    $getTargetResourceResult.AgentSvcDatalink | Should Be $true
                }

                It 'Should return the AgentSvcInternet property as True' {
                    $getTargetResourceResult.AgentSvcInternet | Should Be $true
                }

                It 'Should return the AgentSvcEnd2End property as True' {
                    $getTargetResourceResult.AgentSvcEnd2End | Should Be $true
                }

                It 'Should return the Ensure property as Present' {
                    $getTargetResourceResult.Ensure | Should Be 'Present'
                }

                AfterEach {
                    $path = "HKLM:\SYSTEM\CurrentControlSet\Services\SNMP\Parameters\ValidCommunities"
                    Remove-ItemProperty –Path $path –Name "public" -ErrorAction SilentlyContinue -Force
                }
            }

        }


        # TODO: add more Describe blocks as needed

}
finally
{
    Invoke-TestCleanup
}

Those tests are very simple and normally (i think) they should all pass without error, the problem is with the Ensure property that is returning "Absent" when it should return "Present" as shown on this image:

pester test results

It is using the same data of the manual test, i really don't understand what i am doing wrong there? Hope someone can help me with that issue. Thanks in advance !

EDIT: *error message in pester:

Describing Snmp\Get-TargetResource
   Context Key parameter (SecCommName) is set to public and SecCommRight is 
set to NONE
    [+] Should not throw 262ms
    [+] Should retrieve the registry key 139ms
    [+] Should return a hashtable 84ms
    [+] Should return 13 hashtable properties 16ms
    [+] Should return the AgentSvcPhysical property as True 21ms
    [+] Should return the AgentSvcApplications property as True 19ms
    [+] Should return the AgentSvcDatalink property as True 25ms
    [+] Should return the AgentSvcInternet property as True 24ms
    [+] Should return the AgentSvcEnd2End property as True 17ms
    [-] Should return the Ensure property as Present 179ms
      Expected string length 7 but was 6. Strings differ at index 0.
      Expected: {Present}
      But was:  {Absent}
      -----------^
      131:                     $getTargetResourceResult.Ensure | Should Be 'Present'
      at <ScriptBlock>, C:\Utils\develop-snmpdsc-tests\DscResources\Snmp_Dsc\Tests\Unit\Snmp_Dsc.tests.ps1: line 131
 [-] Error occurred in test script 'C:\Utils\develop-snmpdsc-tests\DscResources\Snmp_Dsc\Tests\Unit\Snmp_Dsc.tests.ps1'
125ms
   CommandNotFoundException: The term 'Restore-TestEnvironment' is not recognized as the name of a cmdlet, function, scr
ipt file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correc
t and try again.
   at Invoke-TestCleanup, C:\Utils\develop-snmpdsc-tests\DscResources\Snmp_Dsc\Tests\Unit\Snmp_Dsc.tests.ps1: line 47
   at <ScriptBlock>, C:\Utils\develop-snmpdsc-tests\DscResources\Snmp_Dsc\Tests\Unit\Snmp_Dsc.tests.ps1: line 145
   at <ScriptBlock>, C:\Program Files\WindowsPowerShell\Modules\Pester\3.4.0\Pester.psm1: line 297
   at Invoke-Pester, C:\Program Files\WindowsPowerShell\Modules\Pester\3.4.0\Pester.psm1: line 310
   at <ScriptBlock>, <No file>: line 1

NOTE: i did some more testing and the problem seems to be with Testdrive.. I get the rights results when i use the script directly(dot sourcing).. that's still odd because testdrive is supposed to discard it's content after testing and it seems as it doesn't ?

jiciftw
  • 65
  • 1
  • 6

0 Answers0