如何测试依赖TypeORM连接的Express.js路由(解决404问题)
解决Express+TypeORM测试中路由未挂载导致的404问题
核心逻辑
测试必须等TypeORM数据源初始化完成、路由完全挂载后再发请求,不能靠定时器凑时间,得用Jest的异步钩子+异步函数来严格控制执行时序。
具体实现步骤
1. 把Express应用创建改成异步函数
把数据源初始化和路由挂载逻辑封装成异步函数,确保只有数据源连接成功后,才返回配置好的Express实例:
// src/app.ts import express from 'express'; import { AppDataSource } from './data-source'; export const createApp = async () => { const app = express(); // 等TypeORM数据源初始化完成 await AppDataSource.initialize(); // 挂载所有路由(包括/ping) app.get('/ping', (req, res) => { res.send('pong'); }); return app; };
正常启动服务的入口文件(比如index.ts)可以这么用:
// src/index.ts import { createApp } from './app'; (async () => { const app = await createApp(); app.listen(3000, () => { console.log('Server running on port 3000'); }); })();
2. 用Jest的beforeAll钩子等应用初始化
在测试文件里,通过beforeAll异步调用createApp,拿到完全初始化好的app实例后,再传给supertest发请求:
// src/__tests__/ping.test.ts import request from 'supertest'; import { createApp } from '../app'; import { AppDataSource } from '../data-source'; let app: Express; beforeAll(async () => { // 等应用初始化完(含数据源连接、路由挂载) app = await createApp(); }); afterAll(async () => { // 测试结束后关闭数据源,避免资源泄漏 await AppDataSource.destroy(); }); test('GET /ping should return 200 and "pong"', async () => { const response = await request(app).get('/ping'); expect(response.status).toBe(200); expect(response.text).toBe('pong'); });
3. 给测试环境单独配置数据源(可选但推荐)
用内存数据库(比如SQLite内存模式)做测试,避免污染开发/生产数据库:
// src/data-source.ts import { DataSource } from 'typeorm'; export const AppDataSource = new DataSource({ type: process.env.NODE_ENV === 'test' ? 'sqlite' : 'postgres', database: process.env.NODE_ENV === 'test' ? ':memory:' : 'mydb', entities: [__dirname + '/entities/*.entity.ts'], synchronize: process.env.NODE_ENV === 'test', // 测试环境自动同步表结构 });
之前重构失效的原因
如果之前拆分了数据库连接和路由逻辑但没解决问题,大概率是测试时没等数据库连接完成就发了请求。必须确保await AppDataSource.initialize()完全执行完,路由已经挂载到Express实例上,再执行测试用例。
内容的提问来源于stack exchange,提问作者DaraJ
相关产品推荐
相关产品推荐

