Pester tests for DSC resource

Welcome Forums DSC (Desired State Configuration) Pester tests for DSC resource

This topic contains 3 replies, has 2 voices, and was last updated by

 
Participant
2 years, 2 months ago.

  • Author
    Posts
  • #49535

    Participant
    Points: 0
    Rank: Member

    Hi,

    I'm trying to write some pester tests for one of my resources... I'm still relatively new to Pester but I've done a few before and the mocks have worked without any issues but this time it's doing my head in...

    The entire resource is here: https://github.com/theonlyway/xDSCSEPVIE/blob/dev/DSCResources/xDSCSEPVIE/xDSCSEPVIE.psm1
    The entire test are here: https://github.com/theonlyway/xDSCSEPVIE/blob/dev/Tests/xDSCSEPVIE.Tests.ps1

    What I appear to be having issues with is I am mocking the following commands, import-csv, get-volume and test-path. When I do some specific tests against those particular commands I can be sure they are being mocked correctly as per the global variables set.

    InModuleScope -ModuleName xDSCSEPVIE -ScriptBlock {
      $VIELocation = 'C:\Temp\doesntmatter.exe'
    
      $global:mockedVolume = [pscustomobject] @{
        FileSystemLabel = 'myLabel'
        DriveLetter     = 'C'
      }
      $global:mockedCSVSuccess = [pscustomobject] @{
        DriveLetter = 'C'
        DateScanned = (Get-Date -Format dd/MM/yyyy)
      }
      $global:mockedCSVFailure = @()
      $global:mockedCSVFailure += [pscustomobject] @{
        DriveLetter = 'C'
        DateScanned = (Get-Date -Format dd/MM/yyyy)
      }
      $global:mockedCSVFailure += [pscustomobject] @{
        DriveLetter = 'D'
        DateScanned = (Get-Date -Format dd/MM/yyyy)
      }
    
      Describe -Name 'Testing mocks' -Fixture {
        Mock -CommandName Import-CSV -MockWith {
          $global:mockedCSVSuccess
        }
        Mock -CommandName Get-Volume -MockWith {
          $global:mockedVolume
        }
        Mock -CommandName Test-Path -MockWith {
          return $true
        }
        It -name 'import-csv' -test {
          (Import-Csv).driveletter | Should Be 'C'
        }
        It -name 'get-volume' -test {
          (Get-Volume).driveletter  | Should Be 'C'
        }
        It -name 'test-path' -test {
          Test-Path -Path C:\windows\temp\VIEDrives.csv  | Should Be 'true'
        }
      }

    However when I get to this block

      Describe -Name "Testing $($Global:DSCResourceName)\Get-TargetResource present/absent logic" -Fixture {
        Mock -CommandName Import-CSV -MockWith {
          $global:mockedCSVSuccess
        }
        Mock -CommandName Get-Volume -MockWith {
          $global:mockedVolume
        }
        Mock -CommandName Test-Path -MockWith {
          return $true
        }
        It -name 'Get-TargetResource should return present' -test {
          (Get-TargetResource -VIELocation $VIELocation).Values | Should Be 'Present'
        }
        Mock -CommandName Import-CSV -MockWith {
          $global:mockedCSVFailure
        }
        It -name 'Get-TargetResource should return absent' -test {
          (Get-TargetResource -VIELocation $VIELocation).Values | Should Be 'Absent'
        }
      }

    It uses this function

    function Get-TargetResource
    {
      [CmdletBinding()]
      [OutputType([System.Collections.Hashtable])]
      param
      (
        [Parameter(Mandatory = $true)]
        [System.String]
        $VIELocation
      )
    
      $volumes = Get-Volume |
      Where-Object -FilterScript {
        $_.DriveType -eq 'Fixed' -and $_.FileSystemLabel -ne 'System Reserved' -and $_.DriveLetter -ne $null
      } |
      Sort-Object -Property DriveLetter
      if (Test-Path -LiteralPath 'C:\Windows\Temp\VIEdrives.csv') 
      {
        Write-Verbose -Message 'CSV exists'
        $csv = Import-Csv -Path 'C:\Windows\Temp\VIEdrives.csv'
        foreach ($drive in $csv) 
        {
          if ($drive.driveletter -in $volumes.driveletter) 
          {
            Write-Verbose -Message "Drive letter ($($drive.driveletter)) exists"
            return @{
              Ensure = 'Present'
            }
          }
          else 
          {
            Write-Verbose -Message "Drive letter ($($drive.driveletter)) does not exist"
            return @{
              Ensure = 'Absent'
            }
          }
        }
      }
      else 
      {
        Write-Verbose -Message 'CSV does not exists'
        return @{
          Ensure = 'Absent'
        }
      }
    }

    I get the following results

    Describing Testing mocks
     [+] import-csv 25ms
     [+] get-volume 8ms
     [+] test-path 7ms
    Describing Testing if functions return correct objects
    VERBOSE: CSV exists
    VERBOSE: Drive letter (C) does not exist
     [+] Get-TargetResource returns a hashtable 33ms
     [+] Test-TargetResource returns true or false 44ms
    Describing Testing xDSCSEPVIE\Get-TargetResource present/absent logic
    VERBOSE: CSV exists
    VERBOSE: Drive letter (C) does not exist
     [-] Get-TargetResource should return present 40ms
       Expected string length 7 but was 6. Strings differ at index 0.
       Expected: {Present}
       But was:  {Absent}
       -----------^
       at line: 77 in C:\Users\Anthony\Documents\GitHub\xDSCSEPVIE\Tests\xDSCSEPVIE.Tests.ps1
       77:       (Get-TargetResource -VIELocation $VIELocation).Values | Should Be 'Present'
    VERBOSE: CSV exists
    VERBOSE: Drive letter (C) does not exist

    I'm pretty sure the logic in the resource is sound because when I run it manually as a function it works properly as I would expect but the pester tests which I believe I am mocking correctly aren't producing the same results as when I run it manually and I can't figure out why.

    Anyone have any ideas?

  • #49648

    Participant
    Points: 0
    Rank: Member

    @anthony – It looks like your mock of

     $global:mockedVolume = [pscustomobject] @{
        FileSystemLabel = 'myLabel'
        DriveLetter     = 'C'
      }
    

    doesn't have all the right properties to satisfy the below filter, which means you'll get $null for volumes and absent for c:\...

    $volumes = Get-Volume |
      Where-Object -FilterScript {
        $_.DriveType -eq 'Fixed' -and $_.FileSystemLabel -ne 'System Reserved' -and $_.DriveLetter -ne $null
      } |
      Sort-Object -Property DriveLetter 
    
    • #49666

      Participant
      Points: 0
      Rank: Member

      Ah I was under the impression that when you mocked a command it would just intercept the command and just return what you wanted regardless of any filters you specified.

      But when you think about it logically that would probably be a really bad idea... Either way I'll remember that for the future.

      Thanks Steven, all working!

    • #49747

      Participant
      Points: 0
      Rank: Member

      No problem! The mock does mock any filters provided to the command itself, but in this case you are piping the mocked output to other commands.

      This is a great place to extract a function – you could make a function in your module called something like Get-FixedReservedDisk
      and have

      function Get-FixedReservedDisk {
       Get-Volume |
        Where-Object -FilterScript {
          $_.DriveType -eq 'Fixed' -and $_.FileSystemLabel -ne 'System Reserved' -and $_.DriveLetter -ne $null
        } |
        Sort-Object -Property DriveLetter
      }
      

      Then when testing the Get-TargetResource, you could mock that function (rather than get-volume). You'd also want separate tests around Get-FixedReservedDisk.

The topic ‘Pester tests for DSC resource’ is closed to new replies.