如何在Mocha中测试未被await的异步函数调用?
如何测试异步postReservation服务是否被调用?
你当前依赖固定时长等待的测试方案既不可靠(异步操作耗时可能波动),又会拖慢测试执行速度。更优的方案是使用**测试替身(Mock)**跟踪postReservation的调用状态,完全不需要等待。
业务代码参考
bookReservation函数
async function bookReservation(...) { await bookReservationForUser(...); postReservation(...); // 注意:此处未使用await,若需确保postReservation执行完成,建议添加await }
postReservation函数
async function postReservation(...) { await DoSomeThing(); await DoSomeOtherThing(); }
优化后的测试方案
方案1:使用Sinon.js创建Mock(推荐)
Sinon.js是Mocha生态中常用的测试替身库,能方便跟踪函数调用:
- 安装依赖:
npm install sinon chai --save-dev
- 编写测试代码:
const sinon = require('sinon'); const { expect } = require('chai'); const { bookReservation, postReservation } = require('./your-service-module'); // 替换为实际模块路径 describe('预订服务测试套件', function() { it('调用bookReservation时应触发postReservation', async function() { // 创建postReservation的mock实例,期望被调用一次 const postReservationMock = sinon.mock(postReservation); postReservationMock.expects('call').once(); // 执行待测试函数 await bookReservation(...); // 传入测试所需参数 // 验证mock是否符合预期 postReservationMock.verify(); // 恢复原函数,避免影响其他测试 postReservationMock.restore(); }); });
方案2:手动Mock函数(无第三方依赖)
如果不想引入额外库,可以手动替换postReservation为跟踪调用状态的函数:
const { expect } = require('chai'); const { bookReservation, postReservation } = require('./your-service-module'); describe('预订服务测试套件', function() { let originalPostReservation; let isPostReservationCalled = false; // 每个测试前保存原函数并替换为mock beforeEach(function() { originalPostReservation = postReservation; isPostReservationCalled = false; global.postReservation = (...args) => { isPostReservationCalled = true; // 可选:若需要保留原函数的异步逻辑,返回原函数执行结果 return originalPostReservation(...args); }; }); // 每个测试后恢复原函数 afterEach(function() { global.postReservation = originalPostReservation; }); it('调用bookReservation时应触发postReservation', async function() { await bookReservation(...); expect(isPostReservationCalled).to.be.true; }); });
额外提示
如果业务逻辑需要确保postReservation执行完成后bookReservation才返回,建议在bookReservation中给postReservation添加await:
async function bookReservation(...) { await bookReservationForUser(...); await postReservation(...); // 添加await确保异步操作完成 }
这种情况下,测试时依然不需要额外等待,直接断言mock的调用状态即可。
内容的提问来源于stack exchange,提问作者Ujjawal Khadanga
相关产品推荐
相关产品推荐

