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

Cant use New-MockObject with custom class from within a module #2564

Open
3 tasks done
dglambert opened this issue Sep 12, 2024 · 2 comments
Open
3 tasks done

Cant use New-MockObject with custom class from within a module #2564

dglambert opened this issue Sep 12, 2024 · 2 comments

Comments

@dglambert
Copy link

Checklist

What is the issue?

Synopsis: When trying to calling New-MockObject -Type 'Config' where Config is a class defined in another psm1 file, I get the following error PSInvalidCastException: Cannot convert the "Config" value of type "System.String" to type "System.Type"

Using Powershell 5.1 with Pester V5.6.1

I have put together the following simple sample to demonstrate the problem

  • Client depends on Config
  • Client.Tests depends on Config & Client
  • Not sure if this is important, but Client has a using statement for Config, and therefore transitively, Client.Tests has 2 using calls to Config, 1 in Client.Tests and another in Client

All files are in the same directory

Config.psm1

class Config 
{
    [ValidateLength(1, 1000)]
    [string] $A
    
    [ValidateLength(1, 1000)]
    [string] $B    

     Config( [string] $pathToJson) 
     {
        try 
        {
            $jsonContent = Get-Content -Path $pathToJson -Raw | ConvertFrom-Json

            $this.A = $jsonContent.A
            $this.B = $jsonContent.B
        } 
        catch 
        {
            Write-Warning $_.Exception.Message
            Write-Warning "Check json file for missing value(s)"
            throw "Error loading configuration from file: $($_.Exception.Message)"
        }
    }
}


Export-ModuleMember -Function Config 

Client.psm1

using module .\Config.psm1

class Client
{
    [Config] $config

    Client([Config] $config) 
    {
        $this.config = $config
    }


    [string] JoinAandB()
    {        
        return $this.config.A + $this.config.B
    }
}

Export-ModuleMember -Function Client

Client.Tests.psm1

using module .\Config.psm1
using module .\Client.psm1

Describe "SomeClassThatUsesAzureDevOpsAgentConfig" {    
 
    It "JoinAandB__A_and_B_Are_Populated__ReturnsAB" {
        # Arrange
        $mockConfig = New-MockObject -Type  'Config' -Properties {A = "foo" B = "Bar"}
        $systemUnderTest = New-Object Client($mockConfig)
        $expectedResult = "AB"

        # Act
        $actualResults = $objectUnderTest.JoinAandB()

        # Assert
        $actualResults | Should -Be $expectedResult
    }
}

I'm not including the JSON since its not relevant, as I am trying to mock the config class, so it should not be needed.

The Error message I get when I run Invoke-Pester .\Client.Tests.ps1

Starting discovery in 1 files.
Discovery found 1 tests in 16ms.
Running tests.
[-] SomeClassThatUsesAzureDevOpsAgentConfig.JoinAandB__A_and_B_Are_Populated__ReturnsAB 5ms (5ms|1ms)
 PSInvalidCastException: Cannot convert the "Config" value of type "System.String" to type "System.Type".
 ArgumentTransformationMetadataException: Cannot convert the "Config" value of type "System.String" to type "System.Type".
 ParameterBindingArgumentTransformationException: Cannot process argument transformation on parameter 'Type'. Cannot convert the "Config" value of type "System.String" to type "System.Type".
 at <ScriptBlock>, C:\Users\dgleason\source\repos\DevOpsTeam\IaC\installs\azure_devops_agent_configuration\Client.Tests.ps1:9
Tests completed in 77ms
Tests Passed: 0, Failed: 1, Skipped: 0, Inconclusive: 0, NotRun: 0

The weird thing is, when I was developing my unit tests, they were all passing, it wasn't until some point till I made it to my 6th or 7th test that it started failing. This makes me think the way I had my module loaded in my IDE (VS Code) bypassed the issue.

Expected Behavior

Calling New-MockObject -Type 'Config' should return my mocked class

Steps To Reproduce

Executing Invoke-Pester .\Client.Tests.ps1 from current working directory in IDE terminal after closing and reopenning, or via new Powershell window to avoid any caching of classes/modules.

Describe your environment

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

Possible Solution?

No response

@dglambert
Copy link
Author

dglambert commented Sep 16, 2024

Closing the loop on this, I was able to make this work by changing -Type 'Config' to -Type ([Config]) - credit for the answer goes to @mklement0 at https://stackoverflow.com/questions/78979730/how-to-use-pester-new-mockobject-with-class-from-within-a-module

However, I'm not sure why this works, I think the documentation at the very least should be updated.

@fflaten
Copy link
Collaborator

fflaten commented Sep 16, 2024

Glad you figured it out. Likely same explanation as this.

Let's leave this open to update matching docs as you've suggested. 🙂

If you or someone would like to contribute a PR, I suggest adding a note about using parantheses around type-values in -Type parameter help + a fixed example in https://github.com/pester/Pester/blob/main/src/functions/New-MockObject.ps1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants