You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:30:00