PowerShell单元测试Mock类时提示‘无法找到类型[B]’的问题
PowerShell模块类继承Mock问题解析
问题描述
创建包含类与Pester单元测试的模块,类B继承自外部模块的类A。单元测试中直接实例化类B可正常运行,但尝试通过继承类B创建Mock类时,报错Unable to find type [B]。
相关代码文件如下:
单元测试文件
using module ".\MyModule.psd1" BeforeAll { Import-Module $PSScriptRoot\MyModule.psd1 -Force } Describe 'My unit test 1' { It 'Runs unit test 1' { # 报错:Unable to find type [B]. class MockedClassB : B { MockedClassB ([int]$foo) : base($foo) { } [string] MyMethod() { return 'MockedString' } } $mockedB = [MockedClassB]::new(13) $mockedB.Run() } } Describe 'My unit test 2' { It 'Runs unit test 2' { # 无错误 $instanceB = [B]::new(13) $instanceB.Run() } }
MyModule.psd1
@{ RootModule = 'Include.psm1' ModuleVersion = '1.0.0' # 用于加载类,否则测试文件会报"无法找到类型" ScriptsToProcess = @( 'Classes\B.ps1' ) RequiredModules = '' FunctionsToExport = @() CmdletsToExport = @() AliasesToExport = @() }
Include.psm1
#Requires -Version 5.0 [cmdletbinding()] param() Write-Verbose $PSScriptRoot Write-Verbose '按依赖顺序导入类' $classList = @( 'B' ) foreach($class in $classList) { Write-Verbose " 类: $class" . "$psscriptroot\Classes\$class.ps1" }
B.ps1
using module ".\..\..\ModuleContainingClassA\ModuleContainingClassA.psd1" class B: A { # 构造函数 B([int]$foo) { } }
补充信息:若将Include.psm1中点源加载类的方式替换为直接在该文件中定义类,错误会消失。
原因分析
模块类的可见性限制:PowerShell模块默认不会导出类,除非在模块清单(psd1)中通过
TypesToExport明确指定。虽然ScriptsToProcess会将类加载到全局作用域,允许直接实例化,但在Pester的It块作用域中定义子类时,PowerShell需要父类B的定义具备可继承的可见性——仅仅能实例化不足以满足继承的类型解析要求。重复加载导致的作用域冲突:当前模块同时通过
ScriptsToProcess和Include.psm1点源加载B.ps1,造成类B被重复定义在不同作用域(全局+模块私有),进一步干扰了类型解析逻辑,导致继承时无法正确找到类B的定义。
解决方案
方案1:明确导出模块中的类
修改MyModule.psd1,添加TypesToExport配置,将类B导出到模块外部作用域:
@{ RootModule = 'Include.psm1' ModuleVersion = '1.0.0' ScriptsToProcess = @( 'Classes\B.ps1' ) RequiredModules = '' FunctionsToExport = @() CmdletsToExport = @() AliasesToExport = @() # 添加此行导出类B TypesToExport = @('B') }
方案2:移除重复的类加载逻辑
保留一种类加载方式即可,避免重复定义:
- 要么删除
ScriptsToProcess配置,仅通过Include.psm1点源加载类; - 要么删除Include.psm1中的点源加载代码,仅依赖
ScriptsToProcess加载类B。
方案3:在Pester中确保类的可见性
在BeforeAll块中使用using module替代Import-Module,确保类定义在测试作用域中正确解析:
BeforeAll { using module $PSScriptRoot\MyModule.psd1 }
内容的提问来源于stack exchange,提问作者Rye bread
相关产品推荐
相关产品推荐

