Jest mock未返回rejected Promise反而进入原函数逻辑报错排查
问题根因
mock未生效,核心原因如下:
- 你在测试文件中声明的
generateReportUseCasemock实例,未绑定到Inversify容器,控制器初始化时从ReportServiceLocator获取到的是真实use case实例,不是你创建的mock对象,因此你设置的mockRejectedValue完全不生效,代码直接执行真实use case逻辑。 - 真实use case运行时,内部依赖的
tradeReadOnlyRepository未初始化,this.tradeReadOnlyRepository.fetch()返回undefined,后续调用.then()就会抛出TypeError: Cannot read properties of undefined (reading 'then')报错。
额外代码bug:控制器中读取报表类型参数时写的是req.query.reportformat,但请求传入的参数名是report_type,会导致拿到的report_type值为undefined。
修复方案
1. 正确绑定mock实例到容器
必须将mock的use case实例注册到Inversify容器,替换真实实现,保证控制器依赖注入时拿到的是mock对象,调整测试代码如下:
const container = new Container(); describe('Controller Error Tests', () => { let reportController: ReportController; let generateReportUseCase: IGenerateReportUseCase; // 替换为你项目中绑定IGenerateReportUseCase实际使用的标识符 const GENERATE_REPORT_USE_CASE_TYPE = Symbol.for("IGenerateReportUseCase"); beforeAll(async () => { cleanUpMetadata(); dotenv.config(); // 初始化mock实例并绑定到容器 generateReportUseCase = mock<IGenerateReportUseCase>(); container.bind<IGenerateReportUseCase>(GENERATE_REPORT_USE_CASE_TYPE).toConstantValue(generateReportUseCase); container.bind<ReportServiceLocator>(TYPES.ReportServiceLocator).to(ReportServiceLocator); reportController = new ReportController(container.get<ReportServiceLocator>(Symbol.for("ReportServiceLocator"))); }); // 每个用例执行前重置mock状态,避免跨用例污染 beforeEach(() => { jest.clearAllMocks(); }) it('User held shares report use case throws error', async () => { const requestObj = httpMocks.createRequest({ cookies: { token: jwt.sign({ id: 'test' }, process.env.JWT_SECRET_KEY!), }, query: { report_type: 'CSV' } }); const responseObj = httpMocks.createResponse(); // 对容器中注入的mock实例设置拒绝返回值 mock(generateReportUseCase).usersHeldShares.mockRejectedValue(new Error('Could not generate report')); await reportController.userHeldShares(requestObj, responseObj); expect(responseObj.statusCode).toEqual(500); }) })
注意:请将代码中
GENERATE_REPORT_USE_CASE_TYPE的值替换为你项目ReportServiceLocator获取IGenerateReportUseCase时实际使用的绑定标识符,确保locator能拿到你注册的mock实例。
2. 修复控制器参数笔误
将控制器中读取报表类型的参数名改为和请求传参一致:
@httpGet('/held-shares') public async userHeldShares(@request() req: express.Request, @response() res: express.Response){ const jwtSecretKey = process.env.JWT_SECRET_KEY; const ascending: boolean = req.query.ascending === "false" ? false : true; // 修正参数名,和请求传入的report_type对应 const report_type: string = String(req.query.report_type); const cookieData = await <IUserDto>jwt.verify(req.cookies.token, jwtSecretKey!); if(!cookieData.id){ return res.status(401).json({error: 'User not authorised'}); } return await this.generateReportUseCase.usersHeldShares(cookieData.id!, ascending, report_type) .then((userDto: IUserDto) => { res.status(200).json(userDto) }) .catch((err: Error) => { res.status(500).json(err); }); }
效果验证
修复后,控制器调用this.generateReportUseCase.usersHeldShares时会直接触发mock方法返回rejected状态的Promise,不会进入真实use case的执行逻辑,异常会被后续的.catch()分支捕获,最终响应状态码正确返回500,符合预期。
内容的提问来源于stack exchange,提问作者Adam Cole
相关产品推荐
相关产品推荐

