Tuesday, July 6, 2021

PowerShell: Practical Pester Unit Tests

The previous post, PowerShell: Safely Converting Strings to by Value Types, contained code to test the conversion of strings to value types (int, bool, double, and DateTime). The PowerShell code is contained in file, Convert.ps1, so Convert.Tests.ps1 was added to include the Pester unit tests.

Pester is fully integrated with PowerShell and Visual Studio Code when the PowerShell Extension is installed. Right clicking on Convert.Tests.ps1 in Visual Studio Code's File Explorer displays a context menu which includes menu items Debug Pester Tests and Run Pester Tests:


The Pester code to test Covert.ps1 is as follows where each instance of the Pester Should command is highlighted in boldface:

Set-StrictMode -Version 3.0

Describe 'class Convert' {
  BeforeAll {
    . "$PSScriptRoot\Convert.ps1"
  }

  Context 'method GetDateTime' {
    BeforeAll {
      # O and o format as string in a manner that is parsible
      [string] $dateTimeFormat = 'o'
    }
      
    It 'GetDateTime parsable date' {
      [string] $currentDateTime = (Get-Date).ToUniversalTime().ToString($dateTimeFormat)

      [Nullable[DateTime]] $result = [Covert]::GetDateTime($currentDateTime)

      $result | 
        Should -Not -Be $null -Because "$currentDateTime is a parsable DateTime"
      $result.ToUniversalTime().ToString($dateTimeFormat) | 
        Should -Be $currentDateTime -Because "$currentDateTime is the same at value returned by GetDateTime"
    }

    It 'GetDateTime parsable DateTime' {
      [datetime[]] $originalValues = 
        [DateTime]::MinValue, [DateTime]::MaxValue,
        [DateTime]::new(1066, 10, 16), [DateTime]::new(1944, 6, 6, 10, 30, 30),
        [DateTime]::new(10, 10, 11, 9, 9, 9), [DateTime]::new(1944, 6, 6, 23, 59, 59), 
        [DateTime]::new(10, 10, 11, 0, 0, 0)

      foreach ($originalValue in $originalValues) {
        [Nullable[datetime]] $result = [Covert]::GetDateTime($originalvalue.ToString($dateTimeFormat))

        $result | 
          Should -Not -Be $null -Because "$originalvalue is a parsable DateTime"
        $result | 
          Should -Be $originalvalue -Because "$originalvalue is the same at value returned by GetDateTime"
      }
    }

    It 'GetDateTime unparsable date $null' {
      [Nullable[DateTime]] $result = [Covert]::GetDateTime($null)

      $result | 
        Should -Be $null -Because '$null is not a parsable DateTime'
    }

    It "GetDateTime unparsable date" {
      [string] $unparsableDate = 'abc'      
      [Nullable[DateTime]] $result = [Covert]::GetDateTime($unparsableDate)

      $result | 
        Should -Be $null -Because "$currentDateTime is not a parsable DateTime"
    }
  }

  Context 'method GetBool' {
    It 'GetBool parsable bool' {
      [string[]] $trueTextValues = 'True', 'TRUE', 'true', 'TrUe'

      foreach ($trueTextValue in $trueTextValues) {
        [Nullable[bool]] $result = [Covert]::GetBool($trueTextValue)

        $result | 
          Should -Not -Be $null -Because "$trueTextValue is a parsable bool"
        $result | 
          Should -BeTrue -Because "$trueTextValue is the same at value returned by GetBool"
      }

      [string[]] $falseTextValues = 'False', 'FALSE', 'false', 'FaLsE'

      foreach ($falseTextValue in $falseTextValues) {
        [Nullable[bool]] $result = [Covert]::GetBool($falseTextValue)

        $result | 
          Should -Not -Be $null -Because "$falseTextValue is a parsable bool"
        $result | 
          Should -BeFalse -Because "$falseTextValue is the same at value returned by GetBool"
      }
    }

    It 'GetBool unparsable bool $null' {
      [Nullable[bool]] $result = [Covert]::GetBool($null)

      $result | 
        Should -Be $null -Because '$null is not a parsable bool'
    }

    It "GetBool unparsable bool" {
      [string] $unparsableBool = 'abc'      
      [Nullable[bool]] $result = [Covert]::GetBool($unparsableDate)

      $result | 
        Should -Be $null -Because "$unparsableBool is not a parsable bool"
    }
  }  
  
  Context 'method GetInt' {
    It 'GetInt parsable int' {
      [int[]] $originalValues = [int]::MaxValue, [int]::MinValue, 0, 123, 456, 
      [short]::MinValue, [short]::MaxValue

      foreach ($originalValue in $originalValues) {
        [Nullable[int]] $result = [Covert]::GetInt($originalvalue.ToString())

        $result | 
          Should -Not -Be $null -Because "$originalvalue is a parsable int"
        $result | 
          Should -Be $originalvalue -Because "$originalvalue is the same at value returned by GetInt"
      }
    }

    It 'GetInt unparsable int $null' {
      [Nullable[int]] $result = [Covert]::GetInt($null)

      $result | 
        Should -Be $null -Because '$null is not a parsable int'
    }

    It "GetInt unparsable int" {
      [string] $unparsableInt = 'abc'      
      [Nullable[int]] $result = [Covert]::GetInt($unparsableDate)

      $result | 
        Should -Be $null -Because "$unparsableInt is not a parsable int"
    }
  }

  Context 'method GetDouble' {
    It 'GetDouble parsable double' {
      [double[]] $originalValues = 
            [double]::MaxValue, [double]::MinValue, 0, 123.33, 456.55, 
            [float]::MinValue, [float]::MaxValue, 
            [decimal]::MinValue, [decimal]::MaxValue

      foreach ($originalValue in $originalValues) {
        [Nullable[double]] $result = [Covert]::GetDouble($originalvalue.ToString())

        $result | 
          Should -Not -Be $null -Because "$originalvalue is a parsable double"
        $result | 
          Should -Be $originalvalue -Because "$originalvalue is the same at value returned by GetDouble"
      }
    }

    It 'GetDouble unparsable double $null' {
      [Nullable[double]] $result = [Covert]::GetDouble($null)

      $result | 
        Should -Be $null -Because '$null is not a parsable double'
    }

    It "GetDouble unparsable double" {
      [string] $unparsableDouble = 'abc'      
      [Nullable[double]] $result = [Covert]::GetDouble($unparsableDate)

      $result | 
        Should -Be $null -Because "$unparsableDouble is not a parsable double"
    }
  }    
}

The Covert.ps1 code was include in text form in the post, PowerShell: Safely Converting Strings to by Value Types, but is included follows:





No comments :

Post a Comment