I wrote the following MyTypes module with a simple Class:
class Person {
[string] $Name
Person([string] $name ) {
$this.Name = $name
}
}
Then I defined the following MyModule module to use it:
using module "C:\temp\StackOverflow\PSModules\MyTypes\MyTypes.psm1"
Import-Module "C:\temp\StackOverflow\PSModules\MyTypes\MyTypes.psm1" -Force
function MyFunction {
param (
[Parameter(Mandatory = $true)]
[Person] $person
)
Write-Output "Hello $($person.Name)"
}
# Export the function
Export-ModuleMember -Function MyFunction
And finally wrote a Pester test that is failing as it cannot seem to utilize the reference to the Class define in the MyTypes module
using module "C:\temp\StackOverflow\PSModules\MyTypes\MyTypes.psm1"
BeforeAll {
Import-Module "C:\temp\StackOverflow\PSModules\MyTypes\MyTypes.psm1" -Force
Import-Module "C:\temp\StackOverflow\PSModules\MyModule\MyModule.psm1" -Force
}
Describe 'MyFunction' {
Mock Write-Output {}
$person = [Person]::new("John Doe")
It 'should call my function' {
MyFunction -Person $person
Assert-MockCalled -CommandName Write-Output -Exactly 1 -Scope It
}
}
I receive an error "Cannot bind argument to parameter 'person' because it is null" when running the Pester test. In my real code, I am actually receiving an error that the Pester cannot resolve the type. I'd like to use a module like MyTypes to keep the Classes organized and referenced in my code which works nicely for the real code, but giving me fits with the Pester tests. Does anyone have insight on this problem or the solution?
I am running Pester 5.7.1 and PowerShell 7.5.0
Very similar issue as the one described in Pester Mock a command within a PowerShell class function, you're missing -ModuleName
in both, your Mock
and your Assert-MockCalled
statements. In addition, the Mock
statement should be inside a BeforeAll
block. MyModule
in this example should correspond with the actual module name.
using module ...\MyTypes.psm1
Import-Module ...\MyTypes.psm1, ...\MyModule.psm1 -Force
Describe 'MyFunction' {
BeforeAll {
$person = [Person]::new('John Doe')
$mockSplat = @{ CommandName = 'Write-Output'; ModuleName = 'MyModule' }
Mock @mockSplat -MockWith { }
}
It 'should call my function' {
MyFunction -Person $person
Assert-MockCalled @mockSplat -Exactly 1 -Scope It
}
}
Same as suggested in the linked answer, using InModuleScope
is another option that wouldn't require you to add the -ModuleName
parameter in the mock calls:
InModuleScope 'MyModule' {
Describe 'MyClass' {
BeforeAll {
$person = [Person]::new('John Doe')
Mock -CommandName Write-Output -MockWith { }
}
It 'should call my function' {
MyFunction -Person $person
Assert-MockCalled -CommandName Write-Output -Exactly 1 -Scope It
}
}
}