如何用Mocha+Chai测试setTimeout抛出的异常?
如何测试Mocha/Chai中延迟抛出的异常?
我之前也碰到过类似的场景——当测试目标代码会在异步任务(比如setTimeout)里延迟抛出异常,而且还没法修改这段代码时,Mocha默认的同步异常检测就失效了,得换个思路来处理。下面给你两种靠谱的解决方案:
方法一:利用Mocha的done回调 + 全局异常监听
这种方法通过监听process的uncaughtException事件来捕获延迟抛出的异常,然后用done告诉Mocha测试完成:
it('should pass when delayed exception is thrown', (done) => { // 用once监听,避免监听器泄漏到其他测试 process.once('uncaughtException', (err) => { // 验证异常的基本特征,按需添加更多断言 expect(err).to.be.an('error'); // 如果需要验证错误信息,比如: // expect(err.message).to.equal('你的预期错误信息'); done(); // 调用done表示测试通过 }); // 执行你要测试的代码 Matcher(1).case(1, () => {}); // 等效代码:setTimeout(() => { throw new Error(); }, 1); });
如果异常没抛出,这个测试会因为done从未被调用而超时失败,正好符合你的需求。
方法二:用Promise包裹异步逻辑(支持async/await)
这种方式更符合现代异步代码的写法,把异常捕获转换成Promise的状态变化,同时可以主动设置等待逻辑来确保未抛出异常时测试失败:
it('should pass when delayed exception is thrown', async () => { let caughtError; // 捕获未处理的异常 process.once('uncaughtException', (err) => { caughtError = err; }); // 执行目标代码 Matcher(1).case(1, () => {}); // 等待足够长的时间让异常抛出(时间要比你的延迟时间长,比如这里设10ms) await new Promise(resolve => setTimeout(resolve, 10)); // 验证异常是否被捕获到 expect(caughtError).to.exist; expect(caughtError).to.be.an('error'); // 可选:验证错误内容 // expect(caughtError.message).to.equal('预期的错误信息'); });
关键注意点
- 必须用
process.once而不是process.on,否则事件监听器会残留到后续测试用例,导致奇怪的问题。 - 设置等待时间时,要确保比你的延迟抛出时间(比如示例里的1ms)长,但也不要太长,避免拖慢测试速度。
- 如果需要严格验证异常的具体信息,一定要添加对应的断言,确保抛出的是你预期的异常。
内容的提问来源于stack exchange,提问作者menfon
相关产品推荐
相关产品推荐

