You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Sinon和Proxyquire模拟AWS SES时测试超时问题求助

我来帮你捋捋这种超时问题的常见排查方向,大概率和你的Stub设置、Promise处理或者Mocha的异步逻辑有关,咱们一步步来:

核心排查点

1. 先确认Stub是否真的拦截到了SES调用

这是最常见的坑——很多时候Stub的路径错了,导致真实的SES请求被发出去(或者Stub根本没生效,业务代码的Promise一直pending)。你可以这么验证:

  • 在Stub里加个console.log,比如用Sinon的话:
    const sendEmailStub = sinon.stub(AWS.SES.prototype, 'sendEmail');
    sendEmailStub.callsFake(() => {
      console.log("Stub被触发了!");
      return Promise.resolve({ MessageId: 'test-id' });
    });
    
    跑测试时如果看不到这个日志,说明Stub没生效。
  • 要区分实例方法和静态方法:如果你业务代码里是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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:14:56