跨模块调用PowerShell类时Pester测试参数绑定失败求助
问题原因及解决方案
核心原因
- 模块作用域隔离:PowerShell每个模块都有独立的运行作用域,MyModule内部加载的
Person类,和测试脚本中单独加载的Person类是CLR层面的两个不同类型实例。即使类名完全一致,类型不兼容会导致参数绑定失败,触发看似“参数为null”的错误(实际是类型不匹配的误导性提示)。 - 类的导出规则:默认情况下,PowerShell模块不会自动导出定义的类。MyTypes模块没有显式导出
Person类,导致MyModule只能在内部作用域访问该类,测试脚本加载的类无法和MyModule中的类形成关联。
解决方案
方案一:修改MyTypes模块显式导出类
修改MyTypes.psm1,添加类的导出逻辑:
class Person { [string] $Name Person([string] $name ) { $this.Name = $name } } # 显式导出Person类 Export-ModuleMember -Variable Person
修改MyModule.psm1,仅保留模块导入(无需using module):
Import-Module "C:\temp\StackOverflow\PSModules\MyTypes\MyTypes.psm1" -Force function MyFunction { param ( [Parameter(Mandatory = $true)] [Person] $person ) Write-Output "Hello $($person.Name)" } Export-ModuleMember -Function MyFunction
测试脚本只需导入MyModule,无需单独加载MyTypes:
BeforeAll { 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 } }
方案二:从MyModule作用域获取Person类型(无需修改原模块)
如果不想改动MyTypes模块,可以通过MyModule的导出变量获取类实例:
BeforeAll { Import-Module "C:\temp\StackOverflow\PSModules\MyModule\MyModule.psm1" -Force # 从MyModule的导出变量中获取Person类型 $personType = (Get-Module MyModule).ExportedVariables['Person'].Value } Describe 'MyFunction' { Mock Write-Output {} $person = $personType::new("John Doe") It 'should call my function' { MyFunction -Person $person Assert-MockCalled -CommandName Write-Output -Exactly 1 -Scope It } }
方案三:统一使用using module加载类
将MyTypes模块放到PowerShell的模块路径下(如$HOME\Documents\PowerShell\Modules\MyTypes),确保可以通过模块名直接引用。
修改MyModule.psm1:
using module MyTypes function MyFunction { param ( [Parameter(Mandatory = $true)] [Person] $person ) Write-Output "Hello $($person.Name)" } Export-ModuleMember -Function MyFunction
测试脚本顶部添加using module(必须在所有导入语句之前):
using module MyTypes BeforeAll { 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 } }
内容的提问来源于stack exchange,提问作者Kurtis
相关产品推荐
相关产品推荐

