需要帮助以使用pester测试自定义PowerShell dsc资源

时间:2018-03-07 21:11:23

标签: powershell dsc pester

我是pester测试的新手,我正试图测试我已经制作的自定义dsc资源,我正在测试的功能如下:

<#
    .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 }

当我在没有pester的情况下手动测试资源时,它会返回正确的结果,如下图所示:get-targetresource result

以下是我的测试代码:

<#
    .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
}

这些测试非常简单,而且通常(我认为)它们都应该没有错误地通过,问题出在Ensure属性返回“Absent”时它应该返回“Present”,如下图所示:

pester test results

它使用的是手动测试的相同数据,我真的不明白我在做错了什么?希望有人可以帮我解决这个问题。提前谢谢!

编辑:  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

注意:我做了一些测试,问题似乎与Testdrive有关..当我直接使用脚本(点源)时,我得到权利结果..这仍然是奇怪的,因为testdrive应该在测试后丢弃它的内容它似乎不是吗?

0 个答案:

没有答案