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