使用ConfigurableModuleBuilder的Nest.js测试报Proxy创建错误
解决Nest.js ConfigurableModuleBuilder动态模块测试中的TypeError问题
错误原因
当使用@golevelup/ts-jest的automocker(useMocker(createMock))时,它会尝试为所有依赖自动创建mock。但你的WorkloadIdentityTokenService依赖MODULE_OPTIONS_TOKEN——这是由ConfigurableModuleBuilder生成的注入令牌(通常是字符串或Symbol),不属于对象/类类型。createMock函数需要基于对象创建Proxy,因此无法处理这类令牌,最终抛出TypeError: Cannot create proxy with a non-object as target or handler。
解决方案
方法1:手动提供模块选项
直接在测试模块中为MODULE_OPTIONS_TOKEN提供具体值,避免automocker尝试mock它:
describe('WorkloadIdentityTokenService', () => { let service: WorkloadIdentityTokenService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ WorkloadIdentityTokenService, { provide: MODULE_OPTIONS_TOKEN, useValue: { minutesToRefreshTokenBeforeExpiry: 30 }, // 测试用自定义选项 }, ], }) .useMocker(createMock) .compile(); service = module.get(WorkloadIdentityTokenService); }); it('should be defined', () => { expect(service).toBeDefined(); }); });
方法2:配置automocker忽略特定令牌
通过自定义mocker函数,让automocker跳过对MODULE_OPTIONS_TOKEN的处理,手动返回所需选项:
describe('WorkloadIdentityTokenService', () => { let service: WorkloadIdentityTokenService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [WorkloadIdentityTokenService], }) .useMocker((token) => { if (token === MODULE_OPTIONS_TOKEN) { return { minutesToRefreshTokenBeforeExpiry: 30 }; } return createMock(token); }) .compile(); service = module.get(WorkloadIdentityTokenService); }); // 测试默认值逻辑 it('should fall back to default value when option is missing', async () => { const module: TestingModule = await Test.createTestingModule({ providers: [ WorkloadIdentityTokenService, { provide: MODULE_OPTIONS_TOKEN, useValue: {} }, ], }).compile(); const service = module.get(WorkloadIdentityTokenService); expect(service['minutesToRefreshTokenBeforeExpiry']).toBe(60); }); });
方法3:导入完整配置的动态模块
如果需要测试整个动态模块的集成效果,直接使用ConfigurableModuleClass的forRoot方法导入配置好的模块:
describe('WorkloadIdentityTokenService', () => { let service: WorkloadIdentityTokenService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ imports: [ ConfigurableModuleClass.forRoot({ minutesToRefreshTokenBeforeExpiry: 45, }), ], }).compile(); service = module.get(WorkloadIdentityTokenService); }); it('should apply provided module options', () => { expect(service['minutesToRefreshTokenBeforeExpiry']).toBe(45); }); });
内容的提问来源于stack exchange,提问作者crackmigg
相关产品推荐
相关产品推荐

