使用Mocha运行Node.js单元测试异常:断言未执行且超时
Mocha测试超时&断言未执行问题诊断
核心原因:异步流程未正确通知Mocha测试结束
Mocha对异步测试的执行有明确规则:如果你的测试包含数据库插入/查询/删除这类异步操作,但没通过指定方式告知Mocha「测试已完成」,就会出现两种异常:
- 断言代码根本没机会执行(Mocha没等异步操作做完就默认测试结束,或者一直等到超时)
- 当数据不符合预期时,异步操作的错误/结果没被捕获,最终触发超时而非断言失败
常见错误场景及修复方案
回调式异步未使用
done参数
如果你的数据库操作是基于回调的,必须在异步流程的终点调用done(),错误情况要把错误对象传给done(err):// 错误写法:没调用done,Mocha会一直等待直到超时 it('测试地址CRUD', function() { insertAddress(userId, addr, function(err) { if (err) throw err; getAddress(userId, function(err, data) { assert.equal(data.userId, userId); // 这句大概率不会执行 deleteAddress(userId, function(err) { if (err) throw err; }); }); }); }); // 正确写法 it('测试地址CRUD', function(done) { // 声明done参数 insertAddress(userId, addr, function(err) { if (err) return done(err); // 错误直接传给done终止测试 getAddress(userId, function(err, data) { if (err) return done(err); assert.equal(data.userId, userId); // 现在会正常执行断言 deleteAddress(userId, done); // 最后一步调用done告知测试完成 }); }); });Promise/async/await未返回异步链
如果用Promise或async/await编写异步逻辑,要么返回完整的Promise链,要么直接使用async函数:// 错误写法:没返回Promise,Mocha不等待异步操作完成 it('测试地址CRUD', function() { insertAddress(userId, addr) .then(() => getAddress(userId)) .then(data => { assert.equal(data.userId, userId); return deleteAddress(userId); }); }); // 正确写法1:返回Promise链 it('测试地址CRUD', function() { return insertAddress(userId, addr) // 必须返回整个Promise链 .then(() => getAddress(userId)) .then(data => { assert.equal(data.userId, userId); return deleteAddress(userId); }); }); // 正确写法2:使用async/await it('测试地址CRUD', async function() { await insertAddress(userId, addr); const data = await getAddress(userId); assert.equal(data.userId, userId); await deleteAddress(userId); });异步错误未被捕获
如果异步操作抛出错误但没被捕获,Mocha无法感知异常,会一直等待超时。比如Promise链未加.catch()(不过async函数的错误Mocha会自动捕获)。
额外排查点
- 检查数据库操作是否真的执行完毕:比如插入地址后是否有延迟,或数据库连接异常导致操作卡住
- 确认断言代码位置:必须放在异步回调/
then块/await之后,不能写在同步代码区域
内容的提问来源于stack exchange,提问作者MattJ
相关产品推荐
相关产品推荐

