Skip to content

Josh's IT-Blog

Information Technology, and other interesting things …

  • Home
  • About
  • Contact
  • Links
  • Home
  • About
  • Contact
  • Links

Pester tests for PowerShell modules

  1. Home   »  
  2. Pester tests for PowerShell modules

Pester tests for PowerShell modules

19. August 201920. October 2020 Burkard JoshGeneral

if you write regularly PowerShell modules, you have to test the functions in it.

i wrote some Pester tests, which are doing this tests for all functions in a PowerShell module:

  • the function has SYNOPSIS, DESCRIPTION and EXAMPLES
  • the function has cmdletbinding
  • the function has an OutputType defined
  • the function name starts with an approved verb
  • the function name has an common prefix
  • all parameters have a help text
  • all parameters have a type declaration
  • all variables inside the function has the same upper/lower case
#region declarations
    $TestsPath = Split-Path $MyInvocation.MyCommand.Path
    $ScriptName = Split-Path $MyInvocation.MyCommand.Definition -Leaf
    $FunctionName = @( $ScriptName -split '\.' )[0]

    Clear-Host

    $RootFolder = (get-item $TestsPath).Parent

    Push-Location -Path $RootFolder.FullName

    Set-Location -Path $RootFolder.FullName

    $ModulePath = Get-ChildItem -Filter "*.psm1"
    Import-Module $ModulePath.FullName -Force

    $Functions = Get-Command -Module $ModulePath.BaseName -CommandType Function
    $CommonPrefix = 'CommonPrefix'
#endregion declarations

#region Pester tests
    foreach ( $FunctionName in @( $Functions.Name | Sort-Object ) ) {
        Describe "default tests for $( $FunctionName )" {
            $command = Get-Command -Name $script:FunctionName -All
            $help = Get-Help -Name $script:FunctionName
            $Ast = $command.ScriptBlock.Ast

            <#
            @( $Ast.FindAll( { $true } , $true ) ) | Where-Object { $_.Extent.Text -eq '[cmdletbinding()]' } | select *
            @( $Ast.FindAll( { $true } , $true ) ) | Group-Object TypeName
            @( $Ast.FindAll( { $true } , $true ) ) | Out-Gridview
            #>
            $Verb = @( $script:FunctionName -split '-' )[0]
            It "verb '$( $Verb )' should be approved" {
                ( $Verb -in @( Get-Verb ).Verb ) | Should -Be $true
            }

            try {
                $FunctionPrefix = @( $script:FunctionName -split '-' )[1].Substring( 0, $CommonPrefix.Length )
            }
            catch {
                $FunctionPrefix = @( $script:FunctionName -split '-' )[1]
            }
            it "function Noon should have the Prefix '$( $CommonPrefix )'" {
                $FunctionPrefix | Should -Be $CommonPrefix
            }

            It "Synopsis should exist" {
                ( $command.ScriptBlock -match '.SYNOPSIS' ) | Should -Be $true
            }
            It "Description should exist" {
                ( [string]::IsNullOrEmpty( $help.description.Text  ) ) | Should -Be $false
            }
            It "Example should exist" {
                [boolean]( $help.examples ) | Should -Be $true
            }
            It "[CmdletBinding()] should exist" {
                [boolean]( @( $Ast.FindAll( { $true } , $true ) ) | Where-Object { $_.TypeName.Name -eq 'cmdletbinding' } ) | Should -Be $true
            }
            It "[OutputType] should exist" {
                [boolean]( @( $Ast.FindAll( { $true } , $true ) ) | Where-Object { $_.TypeName.Name -eq 'OutputType' } ) | Should -Be $true
            }
            Context "parameters" {
                $DefaultParams = @( 'Verbose', 'Debug', 'ErrorAction', 'WarningAction', 'InformationAction', 'ErrorVariable', 'WarningVariable', 'InformationVariable', 'OutVariable', 'OutBuffer', 'PipelineVariable')
                foreach ( $p in @( $command.Parameters.Keys | Where-Object { $_ -notin $DefaultParams } | Sort-Object ) ) {
                    It "help-text for paramater '$( $p )' should exist" {
                        ( $p -in $help.parameters.parameter.name ) | Should -Be $true
                    }

                    $Declaration = ( ( @( $Ast.FindAll( { $true } , $true ) ) | Where-Object { $_.Name.Extent.Text -eq "$('$')$p" } ).Extent.Text -replace 'INT32', 'INT' )
                    $VariableType = ( "\[$( $command.Parameters."$p".ParameterType.Name )\]" -replace 'INT32', 'INT' )
                    $VariableTypeFull = "\[$( $command.Parameters."$p".ParameterType.FullName )\]"
                    $VariableType = $command.Parameters."$p".ParameterType.Name -replace 'INT32', 'INT'
                    It "type '[$( $command.Parameters."$p".ParameterType.Name )]' should be declared for parameter '$( $p )'" {
                        ( ( $Declaration -match $VariableType ) -or ( $Declaration -match $VariableTypeFull ) ) | Should -Be $true
                    }
                }
            }
            Context "variables" {
                $code = $command.ScriptBlock
                $ScriptVariables = $code.Ast.FindAll( { $true } , $true ) |
                    Where-Object { $_.GetType().Name -eq 'VariableExpressionAst' } |
                    Select-Object -Property VariablePath -ExpandProperty Extent

                foreach ( $sv in @( $ScriptVariables | Select-Object -ExpandProperty Text -Unique | Sort-Object ) ) {
                    It "variable '$( $sv )' should be in same (upper/lower) case everywhere" {
                        [boolean]( $ScriptVariables | Where-Object { ( ( $_.Text -eq $sv ) -and ( $_.Text -cne $sv ) ) } ) | Should -Be $false
                    }
                }
            }
        }
    }
#endregion Pester tests

 

Post navigation

Previous: pass parameter values to Invoke-CMScript
Next: getting Security Scopes of SCCM folder

About

Author Image
My name is Josh Burkard.
I'm a DevOps Engineer working with one of Europees largest payroll provider. in my work I have a lot to do with Microsoft server operating systems, System Center, VMware, Microsoft Azure Cloud and other software.
On this site I will write some posts about different technology problems and their solutions.
please note also my tweets and retweets from this area.

Categories

  • General (13)
  • Hardware (9)
    • Network (8)
      • Cisco (2)
    • Storage (2)
  • Hiking (1)
  • Home Assistant (5)
  • Microsoft Azure (1)
    • Automation (1)
  • PowerShell (3)
  • Software (1)
    • Excel (1)
  • System Center (18)
    • SCCM (3)
    • SCDPM (1)
    • SCOM (12)
    • SCSM (1)
    • SMA (1)
  • VMware (8)
  • Windows 2008 R2 (10)
    • Active Directory (7)
  • Windows 2012 R2 (1)
  • Windows 2016 (1)
  • Windows 7 (4)
    • BitLocker (1)
  • WordPress (1)
Proudly powered by WordPress | Theme: goldy-mex by inverstheme.