Public/New/New-FunctionPesterTest.ps1
Function New-FunctionPesterTest { <# .SYNOPSIS This Function Creates 2 Pester Test files for the Function being passed to it .DESCRIPTION This Function creates a skeleton pester test file for the Function that is being passed to it including whether the Function has Parameters and creates some basic Pester Tests for these so that you can pull then in future have oppottunity to test the code you've written in more detail - This is a Non-Functional Pester Test called <Function>.Tests.ps1 The Function also creates a blank file in the same location for you to create your Functional Pester Tests and this is created called <Function>.Functional.Tests.ps1 .PARAMETER Function This Parameter takes a String input and is used in Both Parameter Sets .PARAMETER ResolvedFunction This should be passed the Function that you want to work with as an object making use of the following $ResolvedFunction = Get-Command "Command" .PARAMETER OutPath This is the location that you want to output all the module files to. It is recommended not to use the same location as where the module is installed. Also always check the files output what you expect them to. .PARAMETER PrivateFunction This is a switch that is used to correctly export Private Functions and is used internally in Export-AllModuleFunction .EXAMPLE New-FunctionPesterTest -Function New-FunctionPesterTest -OutPath C:\TextFile\PesterHelpers\ .EXAMPLE Get-Command -Module MyModule | Select-Object -ExpandProperty Name | ForEach-Object { New-FunctionPesterTest -Function $_ -OutPath C:\TextFile\PesterHelpers\ .EXAMPLE In this example we have a PrivateFunction that we need to export - In this case it is Get-CommonParameter $Function = 'Get-CommonParameter' $Module = 'PesterHelpers' $ModuleData = Get-Module $module However as it is a Private Function we need to run the following to essentially flush the function into our available local scope For this piece of code thanks goes to Bruce Payette @BrucePayette $AllFunctions = & $moduleData {Param($modulename) Get-command -CommandType Function -Module $modulename} $module $ResolvedFunction = $AllFunctions.Where{ $_.Name -eq $function} New-FunctionPesterTest -Function $Function -ResolvedFunction $ResolvedFunction -PrivateFunction -OutPath $OutPath -Verbose However it is unlikely that you would need to run something similar to this example though this is added for completeness and should help in understanding the story of what happens under the hood .EXAMPLE New-FunctionPesterTest -Function 'New-FunctionPesterTest -OutPath C:\TextFile -Verbose This is useful for when you have created a Function and have no tests and could potentially be used with simple scripts that really just encapsulated as 1 function #> [CmdletBinding(SupportsShouldProcess=$true, DefaultParametersetName='Basic')] Param( [Parameter(Mandatory=$true,ParametersetName='Basic')] [Parameter(Mandatory=$true,ParametersetName='Passthru')] [String] $Function, [Parameter(Mandatory=$true,ParametersetName='Passthru')] $ResolvedFunction, [Parameter(Mandatory=$true,ParametersetName='Basic')] [Parameter(Mandatory=$true,ParametersetName='Passthru')] [String] $OutPath, [Parameter(Mandatory=$false,ParametersetName='Passthru')] [Switch] $PrivateFunction ) if ($PSCmdlet.ShouldProcess($OutPath,"Creating Pester test File for $Function")) { $SB = New-Object -TypeName System.Text.StringBuilder $Parameters = New-Object System.Collections.ArrayList $CommonParameters = (Get-Command Get-CommonParameter | Select-Object -ExpandProperty Parameters).Keys If (!($ResolvedFunction)) {$ResolvedFunction = Get-Command $Function } If (!($PrivateFunction)) { $Tests = "$OutPath\$($ResolvedFunction.Verb)\Tests\$($ResolvedFunction.Name).Tests.ps1" $FunctionalTests = "$OutPath\$($ResolvedFunction.Verb)\Tests\$($ResolvedFunction.Name).Functional.Tests.ps1" } Elseif ($PrivateFunction) { $Tests = "$OutPath\Private\Tests\$Function.Tests.ps1" $FunctionalTests = "$OutPath\Private\Tests\$Function.Functional.Tests.ps1" } $FunctionParams = $ResolvedFunction.Parameters.Keys $VerboseMessage = "Full Output path is $Tests" Write-Verbose -Message $VerboseMessage $SecondLine = @' Describe '$Function Tests' { '@ $SecondLine = $SecondLine.Replace('$Function',$Function) $SB.Append($SecondLine) | Out-Null Write-Verbose -Message "Added initial lines to the StringBuilder variable being used" If ($FunctionParams.Count -gt 0) { $FunctionParams.Foreach({$Parameters.Add($_)}) | Out-Null $CommonParameters.Foreach({$Parameters.Remove($_)}) | Out-Null Write-Verbose -Message "The Function $Function has $($Parameters.Count) Non-Common Parameters" $ThirdLine = @' Context 'Parameters for $Function'{ '@ $ThirdLine = $ThirdLine.Replace('$Function',$Function) $SB.Append($ThirdLine) | Out-Null Write-Verbose -Message "Added Initial Parameter Lines to StringBuilder Variable" foreach ($Parameter in $Parameters) { $ParamText = @' It 'Has a Parameter called $Parameter' { $Function.Parameters.Keys.Contains('$Parameter') | Should Be 'True' } It '$Parameter Parameter is Identified as Mandatory being $MandatoryValue' { [String]$Function.Parameters.$Parameter.Attributes.Mandatory | Should be $Mandatory } It '$Parameter Parameter is of String Type' { $Function.Parameters.$Parameter.ParameterType.FullName | Should be 'System.String' } It '$Parameter Parameter is member of ParameterSets' { [String]$Function.Parameters.$Parameter.ParameterSets.Keys | Should Be $ParamSets } It '$Parameter Parameter Position is defined correctly' { [String]$Function.Parameters.$Parameter.Attributes.Position | Should be $Positions } It 'Does $Parameter Parameter Accept Pipeline Input?' { [String]$Function.Parameters.$Parameter.Attributes.ValueFromPipeline | Should be $ValueFromPipeline } It 'Does $Parameter Parameter Accept Pipeline Input by PropertyName?' { [String]$Function.Parameters.$Parameter.Attributes.ValueFromPipelineByPropertyName | Should be $PipelineByPropertyName } It 'Does $Parameter Parameter use advanced parameter Validation? ' { $Function.Parameters.$Parameter.Attributes.TypeID.Name -contains 'ValidateNotNullOrEmptyAttribute' | Should Be $VNNEAttribute $Function.Parameters.$Parameter.Attributes.TypeID.Name -contains 'ValidateNotNullAttribute' | Should Be $VNNAttribute $Function.Parameters.$Parameter.Attributes.TypeID.Name -contains 'ValidateScript' | Should Be $VSAttribute $Function.Parameters.$Parameter.Attributes.TypeID.Name -contains 'ValidateRangeAttribute' | Should Be $VRAttribute $Function.Parameters.$Parameter.Attributes.TypeID.Name -contains 'ValidatePatternAttribute' | Should Be $VRPattern } It 'Has Parameter Help Text for $Parameter '{ $function.Definition.Contains('.PARAMETER $Parameter') | Should Be 'True' } '@ $Mandatory = $($ResolvedFunction.Parameters[$parameter].Attributes.Mandatory) $Type = $($ResolvedFunction.Parameters[$parameter].ParameterType.Name) $FullType = $($ResolvedFunction.Parameters[$parameter].ParameterType.FullName) $ParamSets = $($ResolvedFunction.Parameters[$parameter].ParameterSets.Keys) $Positions = $($ResolvedFunction.Parameters[$parameter].Attributes.Position) $ValueFromPipeline = $($ResolvedFunction.Parameters[$parameter].Attributes.ValueFromPipeline) $PipelineByPropertyName = $($ResolvedFunction.Parameters[$parameter].Attributes.ValueFromPipelineByPropertyName) $VNNEAttribute = $($ResolvedFunction.Parameters[$parameter].Attributes.TypeID.Name -contains 'ValidateNotNullOrEmptyAttribute') $VNNAttribute = $($ResolvedFunction.Parameters[$parameter].Attributes.TypeID.Name -contains 'ValidateNotNullAttribute') $VSAttribute = $($ResolvedFunction.Parameters[$parameter].Attributes.TypeID.Name -contains 'ValidateScript') $VRAttribute = $($ResolvedFunction.Parameters[$parameter].Attributes.TypeID.Name -contains 'ValidateRangeAttribute') $VRPattern = $($ResolvedFunction.Parameters[$parameter].Attributes.TypeID.Name -contains 'ValidatePatternAttribute') # Replacing text section $ParamText = $ParamText.Replace('$Parameter',$Parameter) $ParamText = $ParamText.Replace('$MandatoryValue',$Mandatory) $ParamText = $ParamText.Replace('$VNNEAttribute',"'$VNNEAttribute'") $ParamText = $ParamText.Replace('$VNNAttribute',"'$VNNAttribute'") $ParamText = $ParamText.Replace('$VSAttribute',"'$VSAttribute'") $ParamText = $ParamText.Replace('$VRAttribute',"'$VRAttribute'") $ParamText = $ParamText.Replace('$VRPattern',"'$VRPattern'") $ParamText = $ParamText.Replace('$Mandatory',"'$Mandatory'") $ParamText = $ParamText.Replace('$ParamSets',"'$ParamSets'") $ParamText = $ParamText.Replace('$Positions',"'$Positions'") $ParamText = $ParamText.Replace('$ValueFromPipeline',"'$ValueFromPipeline'") $ParamText = $ParamText.Replace('$PipelineByPropertyName',"'$PipelineByPropertyName'") $ParamText = $ParamText.Replace("String Type","$Type Type") $ParamText = $ParamText.Replace("System.String",$FullType) $SB.AppendLine($ParamText) | Out-Null Write-Verbose -Message "Added the Parameter Pester Tests for the $Parameter Parameter" } $ContextClose = @' } '@ $SB.AppendLine($ContextClose) | Out-Null } $HelpTests = @' Context "Function $($function.Name) - Help Section" { It "Function $($function.Name) Has show-help comment block" { $function.Definition.Contains('<#') | should be 'True' $function.Definition.Contains('#>') | should be 'True' } It "Function $($function.Name) Has show-help comment block has a.SYNOPSIS" { $function.Definition.Contains('.SYNOPSIS') -or $function.Definition.Contains('.Synopsis') | should be 'True' } It "Function $($function.Name) Has show-help comment block has an example" { $function.Definition.Contains('.EXAMPLE') | should be 'True' } It "Function $($function.Name) Is an advanced function" { $function.CmdletBinding | should be 'True' $function.Definition.Contains('param') -or $function.Definition.Contains('Param') | should be 'True' } } '@ Write-Verbose -Message "Added the Closing lines for the Parameters Section" $SB.AppendLine($HelpTests) | Out-Null $DescribeClose = @' } '@ $SB.AppendLine($DescribeClose) | Out-Null Write-Verbose -Message "Added the Ending Line to the StringBuilder Variable" New-Item $Tests -ItemType File -Force | Out-Null Write-Verbose "File $Tests was created" Set-Content $Tests -Value $($SB.ToString()) -Force -Encoding UTF8 Write-Verbose -Message "Added the Content to the $Tests File and Set the Encoding to UTF8" New-Item $FunctionalTests -ItemType File -Force | Out-Null Write-Verbose "File $FunctionalTests was created" } } |