pester / Pester

Pester is the ubiquitous test and mock framework for PowerShell.
https://pester.dev/
Other
3.08k stars 470 forks source link

Exception when using ParameterSetName in Pester #1851

Closed tbergstedt closed 3 years ago

tbergstedt commented 3 years ago

General summary of the issue

When using ParameterSetName attribute on parameters in Pester scripts, the execution fails with an exception.

Describe your environment

Pester version : 5.1.1 C:\Users\tober\Documents\PowerShell\Modules\pester\5.1.1\Pester.psm1 PowerShell version : 7.1.2 OS version : Microsoft Windows NT 10.0.18363.0

Steps to reproduce

My setup looks like this:

param (
    # Root directory for checking changed items. Use SourcesDirectory when calling from build.
    [Parameter(ParameterSetName="ByDirectory")]
    $Directory = "$PWD"
)

BeforeDiscovery {
    #Import common policy functions. Contains functions Get-FileEncoding and  assertion function UseFileEncoding
    Import-Module $PSScriptRoot\CommonPolicyFunctions\CommonPolicyFunctions.psd1

    # Add imported assertions to Pester. Only used to provide clearer, more readable error messages from test executions
    Add-AssertionOperator -Name 'UseFileEncoding' -Test $Function:UseFileEncoding

    # Get-ModifiedItem is a function import from the module above used throughout many scripts for retrieving a set of items to to validate. In reality, it has a lot more parameters, but in this case I stop at one
    $changedItems = Get-ModifiedItem -Directory $Directory
}

Describe "VerifyFileConfiguration" {

    Context "Validating '<_>'" {
        It "'<_>' Should use correct file encoding" -Foreach $changedItems {

            $item = $(Get-Item "$i")

            # Get-FileEncoding is imported from the module above.
            $encoding = Get-FileEncoding $item
            $encoding.Encoding | Should -Not -Be "UTF-16"
        }
    }
}

-->

Expected Behavior

Standard test execution, all items in $changedItems should be evaluated on their encoding.

Current Behavior

Execution crashes when entering Describe block with exception:

Starting discovery in 1 files.
System.Management.Automation.ParameterBindingException: A positional parameter cannot be found that accepts argument '$null'.
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at Invoke-File(Closure , FunctionContext )
   at System.Management.Automation.PSScriptCmdlet.RunClause(Action`1 clause, Object dollarUnderbar, Object inputToProcess)
   at System.Management.Automation.CommandProcessorBase.Complete()
at <ScriptBlock>, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 2903
at Invoke-File, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 2912
at Invoke-BlockContainer, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 2837
at Discover-Test, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 1411
at Invoke-Test, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 2356
at Invoke-Pester<End>, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 4839
at <ScriptBlock>, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 8609
at Invoke-Interactively, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 8613
at Describe, C:\Users\tober\Documents\PowerShell\Modules\Pester\5.1.1\Pester.psm1: line 8582
at <ScriptBlock>, C:\git\RayStation\buildtools\policies\VerifyFileConfiguration.ps1: line 100
at <ScriptBlock>, <No file>: line 1

When removing ParameterSetName attribute from the parameter, the execution succeeds.

fflaten commented 3 years ago

Could it be that you invoked this file without specifying the Directory-parameter (relying on default-value)? If so, can you try again like:

$container = New-PesterContainer -Path 'My.Tests.ps1' -Data @{ Directory = "A\Valid\Path" }
Invoke-Pester -Container $container -Output Detailed

I haven't been able to test it myself yet, but my immediate thought is that this is similar to #1812 and #1730, in which case we need to provide a default value for the $Data-parameter here since it's always passed to the scriptblock (content of "My.Tests.ps1"). https://github.com/pester/Pester/blob/5234884fff3202fb4c1b9f04bfd8c7e227095e87/src/Pester.Runtime.psm1#L2378-L2387

tbergstedt commented 3 years ago

Thanks, that worked! I was actually struggling with the problem that the $Directory parameter was getting set to $null at certain conditions in Pester v5, but failed to see how. Setting it at runtime, like

PS\> .\My-PesterScript.ps1 -Directory C:\path\to\valid\directory

doesn't work: I get the exception System.Management.Automation.ParameterBindingValidationException: Cannot bind argument to parameter 'Directory' because it is null. when entering the Describe block.

But it worked using your suggested syntax. I don't think it is as straightforward as before, but then again I'm not using Pester in the most standard way.

fflaten commented 3 years ago

Similar to the related PRs in my last post, this is hopefully a simple fix. Will look into it later. As for specifying the parameters directly to the script, that is pending #1787