如何在Mocha与Chai测试间正确关闭并重置Express服务器
如何在测试间完全重置Express服务器
核心痛点:别用单例服务器实例
我太懂这种困扰了——很多人踩坑都是因为把Express服务器做成了单例:比如在模块里直接创建并导出服务器实例,结果所有测试都复用同一个对象,状态根本清不干净。所以第一步必须放弃单例模式,改成按需创建全新的服务器实例。
具体实现步骤
- 先重构你的Express应用代码,把创建+配置服务器的逻辑封装成一个函数,而不是直接导出实例:
// app.js const express = require('express'); function createApp() { const app = express(); // 所有中间件、路由配置都放在这个函数里 app.use(express.json()); app.get('/api/hello', (req, res) => { res.send('world'); }); return app; } module.exports = createApp; - 在测试文件里,每次测试前生成新应用实例并启动,测试结束后彻底关闭:
// test.spec.js const createApp = require('../app'); const request = require('supertest'); let server; beforeEach(() => { const app = createApp(); server = app.listen(0); // 用0让系统自动分配可用端口,彻底避免端口冲突 }); afterEach(async () => { await new Promise((resolve) => { server.close(resolve); // 必须等待关闭完成,否则下一个测试会踩坑 }); }); test('测试接口返回正确内容', async () => { const res = await request(server).get('/api/hello'); expect(res.text).toBe('world'); }); test('全新实例状态干净', async () => { // 这里用的是完全新的服务器,和上一个测试的状态完全隔离 const res = await request(server).get('/api/hello'); expect(res.statusCode).toBe(200); });
别忘了处理外部依赖的重置
如果你的服务器依赖数据库、缓存这类外部服务,只重置服务器还不够:
- 可以在
beforeEach里执行数据库初始化操作,比如清空测试表、插入固定测试数据 - 用事务包裹整个测试流程,测试结束后回滚事务,既能保证数据干净,又比每次清空表高效
避坑小贴士
- 端口冲突:绝对不要固定端口,用
app.listen(0)让系统自动分配,supertest会自动识别端口,完全不用手动管理 - 异步关闭:
server.close()是异步操作,一定要用Promise等待它执行完成,否则下一个测试可能会启动在还没释放的端口上 - 全局中间件污染:所有中间件都要在
createApp函数内部添加,别在模块作用域里定义全局中间件,不然会被所有实例共享
内容的提问来源于stack exchange,提问作者Elia
相关产品推荐
相关产品推荐

