如何解决Express与Supertest测试中的TCPWRAP/TCPSERVERWRAP问题
解决Jest测试Express应用时的TCPWRAP与TCPSERVERWRAP未关闭句柄问题
使用Supertest测试Express应用时,Jest会检测到两个未关闭的句柄导致无法正常退出:
- TCPWRAP:来自Mongoose的MongoDB连接未关闭
- TCPSERVERWRAP:来自Express服务器的监听端口未释放
以下是针对性的解决方法:
1. 修复TCPSERVERWRAP问题(Express服务器残留)
问题根源是测试时直接引入了启动服务器的文件,app.listen()会持续占用端口,导致句柄无法释放。
解决步骤:
- 拆分服务器启动逻辑,将
app实例与启动代码分离 - 测试文件只引入
app实例,由Supertest自动管理服务器启停
代码改造:
- 修改主文件(如
index.js),仅导出app实例:
// index.js const express = require('express'); const app = express(); // 配置中间件、路由等逻辑... // 移除直接调用的app.listen,改为导出app module.exports = app;
- 创建独立的启动文件(如
start.js):
// start.js const app = require('./index'); const PORT = process.env.PORT || 3000; app.listen(PORT, () => { console.log(`Listening on port, ${PORT}`); });
- 测试文件中引入
app实例而非启动文件:
// test/integration/order.route.test.js const request = require('supertest'); const app = require('../../index'); describe('Order Routes', () => { // 编写测试用例... });
2. 修复TCPWRAP问题(Mongoose连接残留)
问题根源是测试结束后MongoDB连接未关闭,导致连接句柄残留。
解决步骤:
在测试套件的afterAll钩子中手动关闭Mongoose连接,确保测试完成后释放资源。
代码示例:
// test/integration/order.route.test.js const request = require('supertest'); const app = require('../../index'); const mongoose = require('mongoose'); describe('Order Routes', () => { // 测试用例... afterAll(async () => { // 测试全部完成后关闭MongoDB连接 await mongoose.connection.close(); }); });
如果有多个测试文件,也可以通过Jest全局配置统一处理:
- 创建
jest.config.js:
module.exports = { // 其他Jest配置... globalTeardown: './tests/teardown.js' };
- 创建全局清理文件
tests/teardown.js:
// tests/teardown.js const mongoose = require('mongoose'); module.exports = async () => { await mongoose.connection.close(); };
内容的提问来源于stack exchange,提问作者Emmanuel Oloyede
相关产品推荐
相关产品推荐

