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

如何用Jest/Sinon测试返回Promise的getBanana方法是否被调用?

解决Jest/Sinon测试中Promise+定时器导致断言失败的问题

我来帮你梳理下问题所在,以及对应的解决办法:

首先,你的测试有两个核心问题导致断言始终失败:

1. 微任务队列未被刷新,断言时机过早

Jest的runOnlyPendingTimers()会同步执行定时器里的代码,但getBanana()返回的Promise属于微任务,会被放到微任务队列中,不会在定时器执行完成后立刻执行。如果不等待微任务队列处理完毕,断言的时机可能过早,导致结果不符合预期。

2. thing变量的作用域错误

看你原代码里的if (thing),这个thing如果是类的实例属性(比如this.thing),那你测试里定义的全局let thing = true完全不会影响到类内部的判断——定时器里的条件永远不满足,自然不会执行getBanana,断言肯定是false。

修正后的测试代码

结合这两个问题,我给你调整后的测试代码:

test('init function calls getBanana', async () => {
  // 1. 创建类的实例,而不是直接调用原型上的方法
  const testInstance = new TheClass();
  // 2. 如果thing是实例属性,设置为true(根据你实际的变量作用域调整)
  testInstance.thing = true;

  // 3. 直接存根实例上的getBanana方法,简化spy的使用
  const getBananaStub = sinon.stub(testInstance, 'getBanana').resolves();
  
  jest.useFakeTimers();
  // 调用实例的初始化方法
  testInstance.initStuffAfterLoad();
  
  // 执行待处理的定时器
  jest.runOnlyPendingTimers();
  // 等待微任务队列执行完成,确保所有异步逻辑收尾
  await Promise.resolve();

  // 用stub直接断言是否被调用
  expect(getBananaStub.called).toBeTruthy();
  // 恢复存根
  getBananaStub.restore();
});

额外优化建议

  • 不需要单独定义getBananaSpy,Sinon的stub本身就具备spy的所有功能,可以直接用getBananaStub.called来判断是否被调用,简化代码。
  • 如果你的thing是全局变量,那测试里的let thing = true需要确保和原代码里的thing是同一个变量(比如原代码里是window.thing,那测试里也要设置window.thing = true)。
  • 如果你用的是Jest 27+,也可以用jest.runAllTicks()来强制刷新微任务队列,效果和await Promise.resolve()类似。

内容的提问来源于stack exchange,提问作者aroundtheworld

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:51:31