Jest测试套件运行失败报EADDRINUSE错误:如何正确关闭server?
问题原因
- 核心诱因是
app.run.js的顶层直接执行了app.listen():测试文件导入app.run时会立刻启动服务占用8081端口,不等beforeAll钩子执行就已经触发端口占用。 - 多测试文件并行执行时,即使单文件有关闭逻辑,同时启动的服务也会抢占同一端口触发报错。
- 现有
afterAll钩子中先关闭数据库再关闭服务的执行顺序,可能导致服务关闭逻辑执行异常。
修复方案
1. 调整app.run.js的启动逻辑
将端口监听逻辑包裹在运行判定中,仅当该文件被直接作为启动入口执行时才启动服务,被测试文件导入时仅返回app实例:
app.use('/api', require('./app.routes')); // 新增判断:仅直接执行该文件时才启动监听 if (require.main === module) { app.listen(process.env.APP_PORT, () => { logger.info('Server is running on port ' + process.env.APP_PORT); }); } module.exports = app;
2. 优化测试文件的生命周期钩子
修改afterAll执行顺序,等待服务完全关闭后再断开数据库连接,同时可传入端口0让系统自动分配随机端口,完全避免多文件并行的端口冲突:
const supertest = require('supertest'); const app = require('../../app.run'); let request = null; let server = null; beforeAll((done) => { // 传0则系统自动分配空闲端口,无需固定端口 server = app.listen(0, done); request = supertest.agent(server); }); afterAll((done) => { // 先关闭服务,再断开数据库连接 server.close((err) => { sequelize.close(); done(err); }); });
3. 可选兜底方案
如果需要保留固定端口测试,可在执行jest命令时添加--runInBand参数,强制所有测试用例串行执行,避免同时启动多个服务抢占端口:
jest --runInBand
内容的提问来源于stack exchange,提问作者user3353167
相关产品推荐
相关产品推荐

