Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Failure in Discovery when using different parameters across files #2392

Closed
3 tasks done
GSDragoon opened this issue Sep 26, 2023 · 3 comments
Closed
3 tasks done

Failure in Discovery when using different parameters across files #2392

GSDragoon opened this issue Sep 26, 2023 · 3 comments

Comments

@GSDragoon
Copy link

Checklist

What is the issue?

I have a suite of tests across multiple files that are the target of a single Pester Container definition that is used to pass parameters into the tests. The path of the container uses a wildcard to target all the test files. Not all of the test files use the same parameters. The parameters also make use of the Parameter attribute (such as forcing it to be mandatory). Manually building a test container for each combination isn't really feasible.

When I run the tests, the discovery fails for the files that do not have all the parameters (and make use of the Parameter attribute).

Pester v5.5.0
Discovery: Starting test discovery in 5 test containers. 

Starting discovery in 5 files.
Discovery: Discovering tests in C:\s\Local\PesterBug\NotWorking1.Tests.ps1 
[-] Discovery in C:\s\Local\PesterBug\NotWorking1.Tests.ps1 failed with:
System.Management.Automation.ParameterBindingException: A parameter cannot be found that matches parameter name 'Parameter2'.
   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.PSScriptCmdlet.DoEndProcessing()
   at System.Management.Automation.CommandProcessorBase.Complete()
at <ScriptBlock>, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 3034
at Invoke-File, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 3043
at Invoke-BlockContainer, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 2942
at Discover-Test, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 1468
at Invoke-Test, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 2462
at Invoke-Pester<End>, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 5046
at <ScriptBlock>, C:\s\Local\PesterBug\RunTests.ps1: line 19
at <ScriptBlock>, <No file>: line 1
Discovery: Found 0 tests in 15 ms 
Discovery: Discovering tests in C:\s\Local\PesterBug\NotWorking2.Tests.ps1 
[-] Discovery in C:\s\Local\PesterBug\NotWorking2.Tests.ps1 failed with:
System.Management.Automation.ParameterBindingException: A parameter cannot be found that matches parameter name 'Parameter2'.
   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.PSScriptCmdlet.DoEndProcessing()
   at System.Management.Automation.CommandProcessorBase.Complete()
at <ScriptBlock>, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 3034
at Invoke-File, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 3043
at Invoke-BlockContainer, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 2942
at Discover-Test, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 1468
at Invoke-Test, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 2462
at Invoke-Pester<End>, C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1: line 5046
at <ScriptBlock>, C:\s\Local\PesterBug\RunTests.ps1: line 19
at <ScriptBlock>, <No file>: line 1
Discovery: Found 0 tests in 15 ms 
Discovery: Discovering tests in C:\s\Local\PesterBug\Working1.Tests.ps1 
Discovery: Found 1 tests in 12 ms 
Discovery: Discovering tests in C:\s\Local\PesterBug\Working2.Tests.ps1 
Discovery: Found 1 tests in 15 ms 
Discovery: Discovering tests in C:\s\Local\PesterBug\Working3.Tests.ps1 
Discovery: Found 1 tests in 12 ms 
Discovery: Processing discovery result objects, to set root, parents, filters etc. 
Discovery found 3 tests in 96ms.
Discovery: Test discovery finished. 
Running tests.

Running tests from 'C:\s\Local\PesterBug\Working1.Tests.ps1'
Describing Two parameters with parameter and validate attributes
  [+] Should pass 22ms (14ms|7ms)

Running tests from 'C:\s\Local\PesterBug\Working2.Tests.ps1'
Describing One parameter with validate attribute
  [+] Should pass 21ms (8ms|13ms)

Running tests from 'C:\s\Local\PesterBug\Working3.Tests.ps1'
Describing One parameter with no attributes
  [+] Should pass 17ms (10ms|8ms)
Tests completed in 480ms
Tests Passed: 3, Failed: 0, Skipped: 0 NotRun: 0
Container failed: 2
  - C:\s\Local\PesterBug\NotWorking1.Tests.ps1
  - C:\s\Local\PesterBug\NotWorking2.Tests.ps1

Expected Behavior

I would expect the tests files that do not have all the parameters to work. They should ignore the extra parameters like how it works if the Parameter attribute is not applied to the parameter.

Steps To Reproduce

Commands to build the Pester Container, Configuration and run the tests.

$container = New-PesterContainer -Path '*.Tests.ps1' -Data @{
    Parameter1 = 'foo'
    Parameter2 = 'bar'
}

$config = New-PesterConfiguration @{
    Run = @{
        Container = $container
    }
    Output = @{
        Verbosity = 'Diagnostic'
        StackTraceVerbosity = 'Full'
    }
    Debug = @{
        WriteDebugMessages = $true
    }
}

Invoke-Pester -Configuration $config

Working test files.

param (
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $Parameter1,
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $Parameter2
)

Describe 'Two parameters with parameter and validate attributes' {
    It 'Should pass' {
        $Parameter1 | Should -Be 'foo'
        $Parameter2 | Should -Be 'bar'
    }
}
param (
    [ValidateNotNullOrEmpty()]
    [string] $Parameter1
)

Describe 'One parameter with validate attribute' {
    It 'Should pass' {
        $Parameter1 | Should -Be 'foo'
    }
}
param (
    [string] $Parameter1
)

Describe 'One parameter with no attributes' {
    It 'Should pass' {
        $Parameter1 | Should -Be 'foo'
    }
}

Test files that do not work.

param (
    [Parameter()]
    [string] $Parameter1
)

Describe 'One parameter with parameter attribute' {
    It 'Should pass' {
        $Parameter1 | Should -Be 'foo'
    }
}
param (
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $Parameter1
)

Describe 'One parameter with parameter and validate attribute' {
    It 'Should pass' {
        $Parameter1 | Should -Be 'foo'
    }
}

Describe your environment

Pester version : 5.5.0 C:\Program Files\WindowsPowerShell\Modules\Pester\5.5.0\Pester.psm1
PowerShell version : 5.1.19041.3031
OS version : Microsoft Windows NT 10.0.19045.0

Possible Solution?

There are two options I see for workarounds, neither are that great, but not terrible.

  1. Define and set a default value of null for parameters that aren't used in those files.
param (
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $Parameter1,
    [string] $Parameter2 = $null
)
  1. Have one file that meets the Path criteria that defines all the parameters. Then it dot sources the other test files (that do not meet the Path criteria) that do not have any parameters defined.
param (
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $Parameter1,
    [Parameter()]
    [ValidateNotNullOrEmpty()]
    [string] $Parameter2
)

Describe 'My Tests'  {
    . "$PSScriptRoot\File1.ps1"
    . "$PSScriptRoot\File2.ps1"
    ...
    . "$PSScriptRoot\File30.ps1"
}
@fflaten
Copy link
Collaborator

fflaten commented Sep 26, 2023

Hi. This is intended PowerShell behavior and not exclusive to Peater. When you use [Parameter()] or [CmdletBinding()] it becomes an advanced function/script. Arguments are then disabled by default so if you try to splat or call with an undefined parameter it will throw.

You need to provide Data compatible with every script or use multiple calls to New-PesterContainer with the appropriate Data values per script.

@johlju
Copy link
Contributor

johlju commented Sep 28, 2023

@GSDragoon does it work to use ValueFromRemainingArguments ?

@GSDragoon
Copy link
Author

Hi. This is intended PowerShell behavior and not exclusive to Peater. When you use [Parameter()] or [CmdletBinding()] it becomes an advanced function/script. Arguments are then disabled by default so if you try to splat or call with an undefined parameter it will throw.

You need to provide Data compatible with every script or use multiple calls to New-PesterContainer with the appropriate Data values per script.

Thanks for the quick response. Guess I shouldn't be too surprised this is the case. Sounds like I need to be okay with a workaround or make bigger design changes


@GSDragoon does it work to use ValueFromRemainingArguments ?

Yes, this works. Suppose this is another workaround, to add this parameter to each file.

param (
    [Parameter()]
    [string] $Parameter1,
    [Parameter(ValueFromRemainingArguments)]
    [object[]]$RemainingParametersPlaceholder
)

@fflaten fflaten closed this as completed May 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants