Jest中使用setTimeout运行回调报错:this.userService.sendEmail不是函数
问题原因与解决方案
核心问题分析
你遇到的报错本质是测试环境中this.userService的上下文或mock状态异常,和runSafelyAsync的实现逻辑无关,具体原因可能有以下几点:
- Nest.js测试中
UserService未被正确mock注入,导致this.userService为undefined - 你对
runSafelyAsync的mock未处理异步回调的Promise,引发测试时序问题 - 测试中类实例的
this上下文未正确初始化
针对性解决方案
1. 确保UserService被正确mock注入
在Nest.js单元/E2E测试中,必须通过测试模块明确mock依赖,不能依赖自动注入:
import { Test } from '@nestjs/testing'; import { YourService } from './your.service'; import { UserService } from './user.service'; describe('YourService', () => { let yourService: YourService; let userService: UserService; beforeEach(async () => { const moduleRef = await Test.createTestingModule({ providers: [ YourService, // 明确mock UserService { provide: UserService, useValue: { sendEmail: jest.fn().mockResolvedValue(undefined) }, }, ], }).compile(); yourService = moduleRef.get(YourService); userService = moduleRef.get(UserService); }); it('should send email via runSafelyAsync', async () => { await yourService.yourMethodThatCallsRunSafelyAsync(); expect(userService.sendEmail).toHaveBeenCalled(); }); });
2. 修正runSafelyAsync的mock实现
原函数的回调是异步Promise,mock时必须等待回调完成,避免时序错误:
jest.spyOn(asyncUtils, 'runSafelyAsync').mockImplementation(async (callback) => { await callback(); });
3. 不mockrunSafelyAsync的替代方案
如果想保留原函数的setTimeout逻辑,可以用Jest的fake timers手动触发:
it('should handle delayed email sending', async () => { jest.useFakeTimers(); yourService.yourMethodThatCallsRunSafelyAsync(); // 触发所有延迟执行的定时器 jest.runAllTimers(); // 等待异步操作完成 await Promise.resolve(); expect(userService.sendEmail).toHaveBeenCalled(); jest.useRealTimers(); });
内容的提问来源于stack exchange,提问作者Filip Szymański
相关产品推荐
相关产品推荐

