使用Sinon和Proxyquire模拟AWS SES时测试超时问题求助
我来帮你捋捋这种超时问题的常见排查方向,大概率和你的Stub设置、Promise处理或者Mocha的异步逻辑有关,咱们一步步来:
核心排查点
1. 先确认Stub是否真的拦截到了SES调用
这是最常见的坑——很多时候Stub的路径错了,导致真实的SES请求被发出去(或者Stub根本没生效,业务代码的Promise一直pending)。你可以这么验证:
- 在Stub里加个
console.log,比如用Sinon的话:
跑测试时如果看不到这个日志,说明Stub没生效。const sendEmailStub = sinon.stub(AWS.SES.prototype, 'sendEmail'); sendEmailStub.callsFake(() => { console.log("Stub被触发了!"); return Promise.resolve({ MessageId: 'test-id' }); }); - 要区分实例方法和静态方法:如果你业务代码里是
const ses = new AWS.SES();然后调用ses.sendEmail(),那必须StubAWS.SES.prototype.sendEmail,而不是AWS.SES.sendEmail(后者是静态方法,一般不会用到)。 - 如果你的业务代码用了
.promise()(比如ses.sendEmail(params).promise()),那还要注意Stub的是sendEmail本身,还是它返回的对象里的promise方法——比如要确保Stub返回的对象有一个能resolve的promise函数。
2. 检查Stub的返回值是否匹配业务代码的调用方式
AWS SES的方法支持回调和Promise两种模式,如果你业务代码用的是Promise链(.then()/.catch()),那Stub必须返回一个能被settle的Promise,不能用回调式的Stub:
- ❌ 错误示例:如果业务代码用Promise,但Stub用了
callsArgWith(回调模式)// 业务代码是Promise写法,这个Stub会导致Promise永远pending sinon.stub(AWS.SES.prototype, 'sendEmail').callsArgWith(1, null, { MessageId: 'test' }); - ✅ 正确示例:返回resolved/rejected的Promise(或者带promise方法的对象)
// 直接返回Promise sinon.stub(AWS.SES.prototype, 'sendEmail').resolves({ MessageId: 'test' }); // 如果业务代码用了.promise(),可以这么写 sinon.stub(AWS.SES.prototype, 'sendEmail').returns({ promise: () => Promise.resolve({ MessageId: 'test' }) });
3. 排查done()是否被正确执行
有时候看起来then/catch里加了done(),但实际上因为错误被吞掉或者Promise链断裂,导致done()没被调用:
- 在catch回调里加错误日志,看看是不是有隐藏错误:
yourEmailService.send(params) .then(() => done()) .catch(err => { console.error("测试捕获到错误:", err); // 看看有没有输出 done(err); }); - 检查业务代码的Promise链是否完整:比如某个then里返回了新的Promise,但没被正确链式调用,导致后续的then/catch永远不执行。
4. 试试改用async/await替代done()
Mocha对async/await的支持更友好,也更容易排查问题,不用手动管理done()。比如把测试用例改成:
it('should send email successfully', async () => { // 设置Stub sinon.stub(AWS.SES.prototype, 'sendEmail').resolves({ MessageId: 'test' }); // 调用业务代码,await会自动等待Promise完成 const result = await yourEmailService.send(params); // 断言逻辑 expect(result).to.have.property('MessageId', 'test'); });
这样如果Stub有问题,Promise会reject,Mocha会直接抛出错误,而不是超时。
5. 检查是否有未处理的Promise拒绝
有些情况下,未处理的Promise拒绝不会直接报错,但会导致Mocha超时。可以在测试文件开头加一行代码,把隐藏的拒绝抛出来:
process.on('unhandledRejection', err => { throw err; // 把未处理的Promise拒绝转为同步错误,方便排查 });
如果按照上面的步骤排查还是没解决,建议把业务代码和测试用例的关键片段贴出来——比如你怎么创建SES实例、怎么调用sendEmail,以及Stub的具体写法,这样能更精准定位问题。
内容的提问来源于stack exchange,提问作者user1381745
相关产品推荐
相关产品推荐

