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

JavaScript测试疑难:如何测试返回未决议Promise的函数?

如何测试返回未决议Promise的JavaScript函数

这个问题挺常见的——毕竟未决议的Promise本身就是设计成不触发then/catch的,不过咱们可以从测试逻辑或者微小的函数调整入手,既满足业务要求,又能完成测试。下面给你几个可行的方案:

方案1:验证Promise的存在性与pending状态

如果你的测试核心需求只是确认函数确实返回了一个Promise,并且没有意外触发决议,那这个方案最直接:

test('函数返回未决议的Promise', () => {
  const result = yourFunction();
  // 第一步:确认返回值是Promise实例
  expect(result).toBeInstanceOf(Promise);
  
  // 第二步:验证短时间内Promise保持pending状态
  return new Promise((resolve) => {
    setTimeout(() => {
      // 如果走到这里,说明在100ms内Promise没有被resolve/reject,测试通过
      resolve();
    }, 100);
  });
});

这里的超时时间可以根据你的业务逻辑调整,只要能覆盖“函数不会意外决议”的场景就行。

方案2:模拟Promise构造函数,验证内部逻辑

如果需要确认函数内部是否正确处理了Promise的resolve/reject引用(只是没触发),可以用测试框架的mock能力来劫持Promise:

以Jest为例:

test('函数正确创建了未决议的Promise', () => {
  let resolveMock, rejectMock;
  // 模拟全局Promise构造函数
  jest.spyOn(global, 'Promise').mockImplementation((executor) => {
    resolveMock = jest.fn();
    rejectMock = jest.fn();
    // 把mock的resolve/reject传给函数的executor
    executor(resolveMock, rejectMock);
    // 返回一个真正的未决议Promise
    return new Promise(() => {});
  });

  const result = yourFunction();

  // 验证Promise确实被调用了
  expect(Promise).toHaveBeenCalled();
  // 这里可以根据你的业务逻辑,验证resolve/reject是否被正确保存(比如存到了外部变量)
  // 示例:expect(yourModule.exposedResolve).toBe(resolveMock);

  // 测试结束后恢复原Promise,避免影响其他测试
  global.Promise.mockRestore();
});

这个方案适合需要深入验证函数内部逻辑,但又不想修改业务代码的场景。

方案3:给函数加测试专用开关(微小调整,不影响生产)

如果允许对业务函数做极其微小的改动(完全不影响生产行为),可以添加一个测试模式开关,手动触发决议来完整测试then/catch流程:

修改业务函数:

function yourFunction(options = {}) {
  let resolveRef, rejectRef;
  const promise = new Promise((resolve, reject) => {
    resolveRef = resolve;
    rejectRef = reject;
    // 原业务逻辑:不主动触发resolve/reject
  });

  // 仅在测试环境或手动开启测试模式时暴露决议方法
  if (process.env.NODE_ENV === 'test' || options.testMode) {
    promise._testResolve = resolveRef;
    promise._testReject = rejectRef;
  }

  return promise;
}

测试时的代码:

test('函数的业务逻辑能正确触发then回调', async () => {
  const promise = yourFunction({ testMode: true });
  // 手动触发resolve,模拟业务逻辑完成后的行为
  promise._testResolve('预期的返回值');
  // 现在可以正常await并验证结果
  const result = await promise;
  expect(result).toBe('预期的返回值');
});

这个方案的好处是能完整测试Promise决议后的流程,同时生产环境下完全看不到这些测试专用的方法。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 04:21:23