如何在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块,只要你确保:
- 所有异步操作(钩子、测试用例)都用
async/await或done回调正确处理 - 没有手动开启并行模式(比如用
--parallel命令行参数,如果开启了,加上--no-parallel关闭即可)
这样不管有多少个describe块,都会按顺序依次执行,前一个describe的所有测试完成后,才会开始下一个describe的测试。
内容的提问来源于stack exchange,提问作者A.G.Progm.Enthusiast
相关产品推荐
相关产品推荐

