如何用Mocha+Chai测试未处理Promise拒绝及包装函数异常处理
我来帮你搞定这个Mocha+Chai的测试场景,核心要验证两点:一是trackerFactory对返回拒绝Promise的watchFunction的处理逻辑,二是确保没有未处理的Promise拒绝漏出来。下面给你两种常用的测试写法,附带详细解释:
写法一:使用原生done回调+事件监听
这种写法不需要额外插件,适合原生Mocha+Chai环境:
it("handles a rejection by the watched function", (done) => { // 1. 模拟一个返回拒绝Promise的watchFunction const intentionalError = new Error("Watched function rejected"); const watchFunction = () => Promise.reject(intentionalError); // 2. 监听未处理的Promise拒绝,用来检测是否有漏网的拒绝 let unhandledRejectionDetected = false; const rejectionHandler = (err) => { unhandledRejectionDetected = true; console.warn("Unhandled rejection caught:", err.message); }; process.on('unhandledRejection', rejectionHandler); // 3. 创建tracker实例并触发调用 const tracker = trackerFactory({ watchFunction }); tracker.call() .catch((err) => { // 4. 验证拒绝的错误是否符合预期(如果tracker会向外传递拒绝的话) expect(err).to.equal(intentionalError); }) .finally(() => { // 5. 必须移除事件监听,避免干扰后续测试 process.off('unhandledRejection', rejectionHandler); // 6. 断言没有未处理的拒绝发生 expect(unhandledRejectionDetected).to.be.false; done(); }); });
关键步骤解释:
- 步骤1:模拟一个明确返回拒绝Promise的
watchFunction,用自定义错误方便后续断言 - 步骤2:监听Node.js的
unhandledRejection事件——如果trackerFactory的包装逻辑没有正确捕获watchFunction的Promise拒绝,这个事件就会触发 - 步骤4:如果你的
tracker.call()设计是将watchFunction的拒绝向外抛出,这里就捕获并验证错误;如果tracker内部会吞掉拒绝(比如做了错误处理),则不需要这个catch块,直接断言tracker.call()是fulfilled状态 - 步骤5&6:移除监听是测试的关键(否则会污染其他用例),最后断言没有未处理的拒绝,确保包装逻辑正确处理了Promise的拒绝
写法二:使用async/await+chai-as-promised插件
如果你的项目已经用了chai-as-promised,写法会更简洁:
首先确保安装插件:
npm install chai-as-promised --save-dev
然后在测试文件中引入并使用:
const chai = require('chai'); const chaiAsPromised = require('chai-as-promised'); chai.use(chaiAsPromised); const expect = chai.expect; // ... it("handles a rejection by the watched function", async () => { const intentionalError = new Error("Watched function rejected"); const watchFunction = () => Promise.reject(intentionalError); const tracker = trackerFactory({ watchFunction }); // 验证tracker.call()返回的Promise是否按预期拒绝 await expect(tracker.call()).to.be.rejectedWith(intentionalError); // 额外验证没有未处理的拒绝 let unhandledRejection = null; const handler = (err) => { unhandledRejection = err; }; process.on('unhandledRejection', handler); // 再次调用一次,确认没有未处理的拒绝漏出 await tracker.call().catch(() => {}); process.off('unhandledRejection', handler); expect(unhandledRejection).to.be.null; });
优势:
- 用
async/await替代回调链,代码更易读 chai-as-promised提供的rejectedWith断言可以直接验证Promise的拒绝状态和错误信息
内容的提问来源于stack exchange,提问作者Tom Klino
相关产品推荐
相关产品推荐

