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

如何在Mocha-Chai测试套件中按顺序执行多个describe块

解决Mocha测试中describe块串行执行的问题

我来帮你搞定这个测试时序的问题!首先咱们得理清为什么会出现“两个describe块同时启动”的错觉——其实Mocha默认是串行执行所有describe块的,但你的代码里有几个异步操作没处理好,导致测试时序混乱,看起来像是并行执行了。

问题根源分析

  • 数据库清空的异步操作没正确等待:你的clear_the_db函数里调用了mongoObj.remove,这是个异步操作,但你没有等待它完成就执行后续测试,导致数据库还没清空,下一个测试就已经开始了。
  • it块里的异步请求没正确处理:之前的代码里用嵌套回调,但没有等待内部请求完成就调用done(),导致测试提前结束,后续操作可能和其他测试的操作交叉。
  • 错误的钩子使用:之前在describe块内部直接调用clear_the_db(),而不是放在beforeEach钩子中,导致初始化逻辑没有和测试正确绑定。

解决方案:正确处理所有异步操作

要让describe块按顺序执行(其实默认就是顺序的),核心是确保所有异步操作(数据库清空、API请求)都用async/await或者done回调来等待完成。

步骤1:重构数据库清空函数为异步

把clear_the_db改成返回Promise,这样可以用await等待它完成:

function clear_the_db() {
  const mongoObj = mongoose.model('modelname');
  return mongoObj.remove({})
    .then(() => console.log('MongoDb collections removed'))
    .catch(err => {
      console.log('Error is= '+err);
      throw err; // 抛出错误让Mocha捕获,标记测试失败
    });
}

步骤2:修正钩子的异步处理

用async/await改写beforeEach,确保数据库清空完成后再执行测试:

beforeEach(async function (){
  await clear_the_db();
});

步骤3:重构it块的API请求

用async/await替代嵌套回调,让代码更清晰,同时确保所有请求完成后再结束测试:

完整修正后的代码

const chai = require('chai');
const chaiHttp = require('chai-http');
const mongoose = require('mongoose');
chai.use(chaiHttp);
const expect = chai.expect;

let server;

// 全局钩子:启动/关闭服务器
before(async function () {
  server = require('../../../app.js');
  // 如果服务器启动是异步的,这里也要await,比如如果app.js返回Promise的话
});

after(function (done) {
  server.close(done); // 把done传给close,确保关闭完成后结束
});

const json_obj = {"a":"b"};

function clear_the_db() {
  const mongoObj = mongoose.model('modelname');
  return mongoObj.remove({})
    .then(() => console.log('MongoDb collections removed'))
    .catch(err => {
      console.log('Error is= '+err);
      throw err;
    });
}

describe("测试项目数据操作", function() {
  beforeEach(async function (){
    await clear_the_db();
  });

  describe('第一组:创建项目并插入数据', ()=> {
    it('创建项目', async () => {
      const createRes = await chai.request(server)
        .post('/create/myproject')
        .send();
      expect(createRes.statusCode).to.equal(200);
    });

    it('向已创建项目插入数据', async () => {
      // 先确保项目存在(因为beforeEach清空了数据库,所以这里需要先创建项目)
      await chai.request(server).post('/create/myproject').send();
      
      const insertRes = await chai.request(server)
        .post('/data/myproject')
        .send(json_obj);
      expect(insertRes.statusCode).to.equal(200);
    });
  });

  describe('第二组:创建项目、插入数据并查询', ()=> {
    it('创建项目', async () => {
      const createRes = await chai.request(server)
        .post('/create/myproject')
        .send();
      expect(createRes.statusCode).to.equal(200);
    });

    it('向已创建项目插入数据', async () => {
      await chai.request(server).post('/create/myproject').send();
      
      const insertRes = await chai.request(server)
        .post('/data/myproject')
        .send(json_obj);
      expect(insertRes.statusCode).to.equal(200);
    });

    it('查询项目中的数据', async () => {
      await chai.request(server).post('/create/myproject').send();
      await chai.request(server).post('/data/myproject').send(json_obj);
      
      const fetchRes = await chai.request(server)
        .get('/data/myproject');
      expect(fetchRes.statusCode).to.equal(200);
      // 还可以断言返回的数据是否正确,比如expect(fetchRes.body).to.deep.equal(json_obj);
    });
  });
});

多个describe块的串行执行

Mocha默认会按代码顺序串行执行所有describe块,只要你确保:

  1. 所有异步操作(钩子、测试用例)都用async/await或done回调正确处理
  2. 没有手动开启并行模式(比如用--parallel命令行参数,如果开启了,加上--no-parallel关闭即可)

这样不管有多少个describe块,都会按顺序依次执行,前一个describe的所有测试完成后,才会开始下一个describe的测试。

内容的提问来源于stack exchange,提问作者A.G.Progm.Enthusiast

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 03:29:15