Skip to content

Josh's IT-Blog

Information Technology, and other interesting things …

  • Home
  • About
  • Contact
  • Links

Pester tests for PowerShell modules

Posted on 19. August 201920. October 2020 By Burkard Josh
General

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

 

Share this:

  • Facebook
  • Twitter
  • Email
  • Print

Post navigation

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

About

Author Image
My name is Josh Burkard.
I'm a DevOps Engineer working with one of swiss largest telecom and full-service hosting 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.

Follow me on Twitter

My Tweets

Categories

  • General (13)
  • Hardware (9)
    • Network (8)
      • Cisco (2)
    • Storage (2)
  • Microsoft Azure (1)
    • Automation (1)
  • PowerShell (1)
  • Software (1)
    • Excel (1)
  • System Center (19)
    • SCCM (3)
    • SCDPM (1)
    • SCOM (13)
    • 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)

Links

  • Burkard-Fingerlin Family
  • Swisscom (Schweiz) AG
Privacy & Cookies: This site uses cookies. By continuing to use this website, you agree to their use.
To find out more, including how to control cookies, see here: Cookie Policy

About

Author Image
My name is Josh Burkard.
I'm a DevOps Engineer working with one of swiss largest telecom and full-service hosting 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.

Follow me on Twitter

My Tweets

FOLLOW ME ON GITHUB

joshburkard (Josh Burkard)

Josh Burkard

joshburkard
Belgium
https://www.burkard.it
Joined on Jul 10, 2015
13 Public Repositories
0 Public Gists

Copyright © 2023 Josh's IT-Blog.

Theme: Oceanly by ScriptsTown

loading Cancel
Post was not sent - check your email addresses!
Email check failed, please try again
Sorry, your blog cannot share posts by email.