pester / Pester

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

Parameterized tests not working (Check pester assembly version) #1770

Closed hirenpatel101 closed 3 years ago

hirenpatel101 commented 3 years ago

Question

I am trying to run a test that takes in parameters. I have followed this code within Pester/tst/Pester.RSpec.ts.ps1

$container = New-PesterContainer -Path $file -Data @{ Value = 1 }
$r = Invoke-Pester -Container $container -PassThru

So my code looks like this (runPester.ps1):

$container = New-PesterContainer -Path "<absolute-path>\testPester.ps1" -Data @{ environmentName = "earth" }
Invoke-Pester -Container $container -PassThru

testPester.ps1 looks like:

param(
    [parameter(mandatory = $true)][string]$environmentName
)

Describe "###### Application" {
    Context "When Accessing the ##### Endpoint" {
        It "Returns Status Code 200" {
            $webInfo = Invoke-WebRequest -Uri "https://###$($environmentName)#####.###/#####"
            $webInfo.StatusCode | Should -Be 200
        }
    }
}

Hashes represent sensitive information

When runPester.ps1 is ran, I get this output:

InvalidOperation: C:\Users\####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1:2865:5
Line |
2865 |      $c.Data = $Data
     |      ~~~~~~~~~~~~~~~
     | The property 'Data' cannot be found on this object. Verify that the property exists and can be set.

System.Management.Automation.RuntimeException: The property 'Container' cannot be found on this object. Verify that the property exists and can be set.
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
at Invoke-Pester<End>, C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1: line 4455
at <ScriptBlock>, C:\Users\#####\source\repos\#############\testRunPesterTests.ps1: line 22

I also tried running the following:

$container = New-PesterContainer -Path "<absolute-path>\testPester.ps1" -Data @{ environmentName = "earth" }
$configuration = [PesterConfiguration]@{
    Run = @{
        Container = $container
        Exit = $true
    }
    TestResult = @{
        Enabled = $true
        OutputPath = "<absolute-path>\TestResults.xml"
    }
}

Invoke-Pester -Configuration $configuration

which returned this error:

InvalidOperation: C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1:2865:5
Line |
2865 |      $c.Data = $Data
     |      ~~~~~~~~~~~~~~~
     | The property 'Data' cannot be found on this object. Verify that the property exists and can be set.

System.Management.Automation.RuntimeException: The property 'Data' cannot be found on this object. Verify that the property exists and can be set.
   at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
   at System.Management.Automation.PSScriptCmdlet.RunClause(Action`1 clause, Object dollarUnderbar, Object inputToProcess)
   at System.Management.Automation.CommandProcessorBase.Complete()
at New-BlockContainerObject, C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1: line 2865
at <ScriptBlock>, C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1: line 4731
at Filter-Excluded, C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1: line 3348
at Find-File, C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1: line 3342
at Invoke-Pester<End>, C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1: line 4731
at <ScriptBlock>, C:\Users\#####\source\repos\#############\testRunPesterTests.ps1: line 20

I am less sure of the [PesterConfiguration] syntax.

Overall question: Is this correct syntax for running tests with parameters? If not, what should I be doing instead?

Environment data

The output of (Invoke-WebRequest -Uri "https://git.io/JTinj" -UseBasicParsing).Content | Invoke-Expression is:

Pester version     : 5.1.0-rc1 C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\Pester.psm1
PowerShell version : 7.0.0-rc.3
OS version         : Microsoft Windows NT 10.0.18363.0
nohwnd commented 3 years ago

Thanks for the report. Looks like a bug win the place where I define variables from data. I probably missing this case when there is no data in my tests.

hirenpatel101 commented 3 years ago

I'm not sure I understand what you mean. I do define Data through New-PesterContainer using -Data

nohwnd commented 3 years ago

You do, but I internally use the same name for data on a block (like Describe) and I think I am assuming data are defined, in one place where they are actually $null. Will see once I analyze this further. 🙂

hirenpatel101 commented 3 years ago

Ah right. Thanks for the explanation

nohwnd commented 3 years ago

Okay I can repro. This is problem with your session. Did you try this in VSCode?

The exact problem is that you already have [PesterConfiguration] type loaded from an older version. This is happening in VSCode automatically when any .Tests.ps1 file is opened and when you have the PowerShell extension installed. This will import Pester which defines this type.

If you then import Pester from non-default folder by using Import-Module Pester, it will import the module just fine, but not the type. The type will be outdated while your module will be the correct version.

You can verify that the type is not coming from the correct module version like this: [PesterConfiguration].Assembly

Look I have that type from 5.0.4 but the module from 5.1.0-rc1:

PS C:\Projects\pester\tst> [PesterConfiguration].Assembly

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Users\jajares\Documents\PowerShell\Modules\Pester\5.0.4\bin\netstandard2.0\Pester.dll

PS C:\Projects\pester\tst> get-module pester

ModuleType Version    PreRelease Name                                ExportedCommands
---------- -------    ---------- ----                                ----------------
Script     5.1.0      rc1        Pester                              {Add-ShouldOperator, AfterAll, AfterEach, Assert-MockCalled…}

To avoid this problem you should just install the module in the default module location and restart your session.

PS C:\Projects\pester> [PesterConfiguration].Assembly

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Users\jajares\Documents\PowerShell\Modules\Pester\5.1.0\bin\netstandard2.0\Pester.dll

PS C:\Projects\pester> get-module pester -list

    Directory: C:\Users\jajares\Documents\PowerShell\Modules

ModuleType Version    PreRelease Name                                PSEdition ExportedCommands
---------- -------    ---------- ----                                --------- ----------------
Script     5.1.0      rc1        Pester                              Desk      {Invoke-Pester, Describe, Context, It…}
Script     5.0.4                 Pester                              Desk      {Invoke-Pester, Describe, Context, It…}
Script     4.10.1                Pester                              Desk      {Describe, Context, It, Should…}
nohwnd commented 3 years ago

We should consider adding a check to ensure the version of the assembly used is the same as the module versison. But when the objects won't change, this might be too strict. Postponing for 5.2 so I have time to decide.

fflaten commented 3 years ago

We should consider adding a check to ensure the version of the assembly used is the same as the module versison. But when the objects won't change, this might be too strict. Postponing for 5.2 so I have time to decide.

We could add a minimum required version as a start. Just need to:

Check if assembly loaded

$configurationType = 'PesterConfiguration' -as [type] if ($null -ne $configurationType -and $configurationType.Assembly.GetName().Version -lt $minimumVersionRequired) { throw [System.NotSupportedException]'An incompatible version of the Pester.dll assembly is already loaded. A new PowerShell session is required.' } elseif ($null -eq $configurationType) { if ($PSVersionTable.PSVersion.Major -ge 6) { & $SafeCommands['Add-Type'] -Path "$PSScriptRoot/bin/netstandard2.0/Pester.dll" } else { & $SafeCommands['Add-Type'] -Path "$PSScriptRoot/bin/net452/Pester.dll" } }

hirenpatel101 commented 3 years ago

That's interesting, as my module was in the default location, And I checked which assembly it was using for [PesterConfiguration] and it returned:

PS C:\Users\#####\source\repos\#####> [PesterConfiguration].Assembly

GAC    Version        Location
---    -------        --------
False  v4.0.30319     C:\Users\#####\Documents\PowerShell\Modules\Pester\5.1.0\bin\netstandard2.0\Pester.dll

So then I just tried running runPester.ps1 again, and now the test works (and passes). Very strange

Is there a way to require the correct version of [PesterConfiguration] within the ps1 file? This script is going to be run in Azure Pipelines as a powershell task

nohwnd commented 3 years ago

@hirenpatel101 was that just powershell window or was that in VSCode?

This can happen in other ways as well. For example you had Pester loaded and then you installed the new version, and loaded it again. Assemblies won't unload in .NET, so you still had the old version, even though you removed and imported your module with a new version.

@fflaten I like that, but I don't like maintaining yet another version of the assembly. I would probably just brand it the same as the module.

This also needs a bit closer look at how it behaves in VSCode, because unlike in a console session, the powershell extension will import pester automatically, and opening VSCode with any .Tests.ps1 file in any tab will force you to have this problem. This is one reason why I have all Pester versions uninstalled.

But I could start by branding the assembly as 5.1.0 in the current release? So we have a baseline for the next release?

hirenpatel101 commented 3 years ago

This has all been in VSCode for me

fflaten commented 3 years ago

@fflaten I like that, but I don't like maintaining yet another version of the assembly. I would probably just brand it the same as the module.

Equal assembly version to module version sounds fine. The requirement in the manifest should be manual thought, being updated on known changes. Or did you want the module import to fail every time there's a mismatch?

The 0.923 version in the module was just to have something less than the current 1.0.0 for the PoC.

nohwnd commented 3 years ago

@fflaten nah you are right, I am confused. The minimal required assembly version should be manual. It will be interesting to see how often we need that updated, and might revert back just to the module version check if it happens every version.

fflaten commented 3 years ago

Is there a way to require the correct version of [PesterConfiguration] within the ps1 file? This script is going to be run in Azure Pipelines as a powershell task

@hirenpatel101 Not really. If you run Install-Module Pester (if not installed in a previous task) and Import-Module Pester at the top of your powershell-task, you'll be fine. Each task is isolated, so that way you're sure that you imported the latest module (and assembly) before anything else indirectly does it 👍

hirenpatel101 commented 3 years ago

Thanks @fflaten. I'm happy for this to be closed, unless you'd like to keep it open for discussion

nohwnd commented 3 years ago

@hirenpatel101 I added it to 5.2 and I am keeping it open so we can add the assembly version check.