使用Supertest测试Express应用时TypeORM找不到连接的问题求解
问题原因
- 模块加载顺序错误:Jest 执行测试前会预先加载所有涉及的导入模块,只要你的主
app实例导入了课程路由,就会连带初始化CoursesController和它依赖的VideosRepositoryTORM,如果这部分代码在文件顶层直接调用了 TypeORM 全局的getRepository()方法,这个调用会发生在测试beforeAll创建连接的逻辑之前,此时还没有 default 连接,就会直接抛出错误,哪怕你本次测试根本没用到课程相关的逻辑。 - 依赖注册时机不匹配:你在
beforeAll中才执行registerDeps()注册 tsyringe 依赖,但如果仓库、控制器类在文件顶层就完成了实例化,初始化逻辑会早于连接创建的时机。
解决方案
方案1:延迟仓库的 Repository 获取逻辑
不要在文件顶层、类属性初始化阶段直接调用 getRepository,改成类实例化时再获取:
// 错误写法 VideosRepositoryTORM.ts @injectable() class VideosRepositoryTORM { private repo = getRepository(Video) // 导入模块时就执行,此时无连接 } // 正确写法 @injectable() class VideosRepositoryTORM { private repo: Repository<Video> constructor() { this.repo = getRepository(Video) // 类实例化时才调用,此时连接已创建 } }
也可以把 TypeORM 连接作为依赖注入到仓库类,避免调用全局方法:
// registerDeps 中添加连接注册逻辑 container.register<Connection>("TypeORMConnection", { useFactory: () => getConnection() }) // 仓库类改造 @injectable() class VideosRepositoryTORM { private repo: Repository<Video> constructor(@inject("TypeORMConnection") conn: Connection) { this.repo = conn.getRepository(Video) } }
方案2:调整 app 实例的导入时机
不要在测试文件顶层导入预先初始化好的 app,改成连接创建完成后再动态导入:
let conn: Connection; let app: Express; describe('tests admin routes', () => { beforeAll(async () => { conn = await createConnection(); registerDeps(); // 此时才导入app,触发后续路由、控制器的初始化,连接已存在 app = (await import('../../../app')).default; }); afterAll(async () => { await conn.close(); }); it('should be able to authenticate admins', async () => { const { status } = await supertest(app) .post('/admins/auth') .send({ email: 'myemail@company.com', password: 'mypassword', }); console.log(status); }); });
方案3:模拟无用模块
如果测试完全不需要用到课程相关模块,可以在 jest.config.js 中配置模拟文件跳过这部分加载:
module.exports = { // 其他配置 moduleNameMapper: { '^src/modules/course/.*$': '<rootDir>/src/__mocks__/emptyModule.ts' } }
内容的提问来源于stack exchange,提问作者hcotta
相关产品推荐
相关产品推荐

