如何使用Jest测试Mongoose连接?解决测试执行超时报错问题
问题根因
超时和定时器逻辑无关,jest.fakeTimer()无法解决该问题,核心触发原因有3个:
- 测试用例声明了
done入参但从未调用,Jest会一直等待回调触发,直到达到默认5秒超时阈值 - mock声明顺序错误:先导入了
../src/app、../src/server业务文件,之后才调用jest.mock(),mock逻辑没有在模块加载阶段生效,真实的mongoose连接、app.listen()逻辑会实际执行,导致测试进程挂起 - 手动编写的mongoose mock不完整,缺失原生mongoose模块的其他属性,业务代码执行时会触发未捕获异常,中断测试流程
修复步骤
- 把所有
jest.mock()声明移动到测试文件最顶部,在导入任何业务代码之前完成mock注册,保证模块加载时拿到的是mock后的对象 - 移除测试用例中不必要的
done参数,当前断言是同步验证mock调用,不需要等待异步回调;如果后续要测异步逻辑,断言完成后必须主动调用done() - 优先使用Jest自动mock替代手动写mongoose mock,避免手动实现漏属性导致的异常;如果需要自定义mock返回值,在
beforeEach里给mock方法设置实现即可 - 给业务入口文件加运行判断,避免导入即执行副作用
修正后的测试代码
// 所有mock声明必须放在最顶部,先于业务模块导入 jest.mock('../src/app') jest.mock('mongoose') // 自动生成全量jest.fn() mock,不需要手动实现Schema、model等属性 import mongoose from 'mongoose' import appMock from '../src/app' // 建议先修改server.ts的启动逻辑:只有直接运行该文件时才执行连接、监听逻辑 // server.ts 参考写法: // if (require.main === module) { // mongoose.connect(uri) // app.listen(port) // } import '../src/server' describe('server entry test', () => { afterEach(() => { jest.clearAllMocks() }) it('should init db connection and start app listener', () => { expect(mongoose.connect).toHaveBeenCalled() expect(appMock.listen).toHaveBeenCalled() }) })
额外优化
如果暂时不想改server.ts的启动逻辑,需要在测试结束后主动清理资源,避免进程挂住:
afterAll(async () => { await mongoose.disconnect() // 如果你导出了app.listen返回的server实例,这里补充调用server.close() })
内容的提问来源于stack exchange,提问作者Rajesh Kumar Jha
相关产品推荐
相关产品推荐

