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

BeOfType doesn't see types, loaded from a file with classes, but the "It" function - does #2414

Open
3 tasks done
exchange12rocks opened this issue Dec 18, 2023 · 3 comments
Labels
Assertions For issues related with assertions Documentation

Comments

@exchange12rocks
Copy link

exchange12rocks commented Dec 18, 2023

Checklist

What is the issue?

I have a .ps1 files containing definitions of my classes. I load that file in a BeforeAll block. Later in my tests I can successfully create objects using these classes, but the Should-BeOfType function does not see those types even so the It function - does.

Running the test defined below, I receive the following output:

Starting discovery in 1 files.
Discovery found 1 tests in 880ms.
Running tests.
The type of TestO is: MyTestClass
[-] Test Classes.Object Creation.creates TestClass 717ms (616ms|102ms)
 ArgumentException: Could not find type [MyTestClass]. Make sure that the assembly that contains that type is loaded.
Tests completed in 4.62s
Tests Passed: 0, Failed: 1, Skipped: 0 NotRun: 0

When executing the test step-by-step, I see that my class is indeed not available in the scope of the Should-BeOfType function.

Expected Behavior

Types available in an It block are available to use with the Should -BeOfType command. The test defined below should pass successfully.

Steps To Reproduce

Describe 'Test Classes' {
    BeforeAll {
        . $PSScriptRoot\Classes.ps1
    }

    Describe 'Object Creation' {
        It 'creates TestClass' {
            $TestO = [MyTestClass]::new()
            Write-Host ('The type of TestO is: {0}' -f $TestO.GetType().Name)
            $TestO | Should -BeOfType [MyTestClass]
        }
    }
}

where Classes.ps1 is:

class MyTestClass {
}

Describe your environment

Pester version     : 5.5.0 C:\Users\kf\Documents\PowerShell\Modules\Pester\5.5.0\Pester.psm1
PowerShell version : 7.4.0
OS version         : Microsoft Windows NT 10.0.19045.0

Possible Solution?

No response

@exchange12rocks exchange12rocks changed the title BeOfType doesn't see types, loaded from a file with classes BeOfType doesn't see types, loaded from a file with classes, but the It function - does Dec 18, 2023
@exchange12rocks exchange12rocks changed the title BeOfType doesn't see types, loaded from a file with classes, but the It function - does BeOfType doesn't see types, loaded from a file with classes, but the "It" function - does Dec 18, 2023
@fflaten
Copy link
Collaborator

fflaten commented Jan 2, 2024

Thanks for the report.

TLDR: Using [MyTestClass] as a parameter value or argument passes the value as a string. The type isn't resolvable by name internally in modules like Pester (see long version for why). If you wrap it in parentheses you'll pass the type-object itself which should work.

Try $TestO | Should -BeOfType ([MyTestClass]) or $TestO.GetType().Name | Should -Be 'MyTestClass'


Long version 🙂

By dot-sourcing Classes.ps1 you only define your classes locally in the current scope. Functions like Should run in a different module-specific session state and scopes which can't see the class in your script scope. The issue is similar to running the script in your session without dot-sourcing.

# Run in child scope similar to your test file. Class is not available when the script is finished -> child scope with class imported is deleted
> & ./Classes.ps1; [MyTestClass]      
InvalidOperation: Unable to find type [MyTestClass].

The typical solution would be to place the class in a module like Classes.psm1 and use e.g. using module .\Classes.psm1 at the top of your test-file to import it. That should've imported it in the global session state, making it available to every module and script. Unfortunately it doesn't. Maybe PowerShell imports the classes in the current scope in the global state which results in the same behavior.

Unfortunately working with classes in PowerShell has lots of weird behavior like this.

A few workarounds:

  • Wrap the type in parentheses to pass the actual type-object
  • Import your classes before running Pester using either using module .\Classes.psm1 or dot-source . .\Classes.ps1. That should make them available in all scopes and session states, including Pester's internal lookup that currently fails.
  • Use $TestO.GetType().Name | Should -Be 'MyTestClass' to assert the type name in this particular scenario.

@fflaten
Copy link
Collaborator

fflaten commented Jan 2, 2024

Keep open until we've updated docs and function help with an example that passes the type-object properly (with parentheses).

Maybe also be clean up own internal tests, besides https://github.com/pester/Pester/blob/main/tst/functions/assertions/BeOfType.Tests.ps1 which is already good.

@fflaten fflaten added Documentation Assertions For issues related with assertions labels Jan 2, 2024
@exchange12rocks
Copy link
Author

Thank you @fflaten for this explanation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Assertions For issues related with assertions Documentation
Projects
None yet
Development

No branches or pull requests

2 participants