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

使用Sinon Stub Firestore失效问题排查求助

问题:Sinon Stub Firestore Document Reference的get方法未生效

问题场景

Node.js Firebase项目,使用Mocha做测试框架,Firebase模拟器运行正常,但尝试用Sinon模拟指定Document Reference的get方法返回错误时,Stub完全不生效,云函数始终调用原始的Firestore get方法,导致测试失败。

测试代码中关键Stub逻辑:

beforeEach(async () => {
  sandbox = sinon.createSandbox();
  // 尝试Stub指定文档的get方法
  docStub = sandbox.stub(admin.firestore().collection(landingPagesPath).doc("3"), 'get');
});

云函数中调用get的核心逻辑:

const landingPageRef = admin.firestore()
  .collection(landingPagesPath).doc(id);
const landingPage = await landingPageRef.get().catch((error) => {
  throw new functions.https.HttpsError(
    "aborted",
    "failed fetching landing page",
    error
  );
});

测试报错:

THE ERROR AssertionError: Expected an error but got success
Promoter Functions Tests
  createPromoter Tests
    test
      should fail if fetching landingpage failed:
        AssertionError: expected AssertionError: Expected an error but got… { …(3) } to be an instance of HttpsError

核心原因

每次调用admin.firestore().collection(...).doc(id)都会生成全新的DocumentReference实例。你在测试代码里Stub的是测试环境中创建的那个实例的get方法,但云函数运行时会自行创建新的DocumentReference实例,两者不是同一个对象,所以Stub无法命中目标方法。

解决方案

方案1:Stub DocumentReference原型的get方法

直接Stub DocumentReference类原型上的get方法,通过判断文档ID来决定是否返回错误,其他情况保留原始逻辑:

beforeEach(async () => {
  sandbox = sinon.createSandbox();

  // 获取DocumentReference的原型对象
  const docRefPrototype = Object.getPrototypeOf(admin.firestore().collection('dummy').doc('dummy'));
  
  // 原型上的get方法,针对ID为"3"的文档返回错误
  sandbox.stub(docRefPrototype, 'get').callsFake(async function() {
    // @ts-ignore 忽略类型检查,因为this指向当前DocumentReference实例
    if (this.id === "3") {
      throw new Error('Failed to fetch landing page');
    }
    // 其他文档调用原始的get方法
    return (docRefPrototype.get as sinon.SinonStub).wrappedMethod.call(this);
  });
});

方案2:Stubdoc方法返回预定义Stub实例

通过Stubcollection().doc()方法,让它在匹配特定ID时返回带有Stubbed get方法的实例:

beforeEach(async () => {
  sandbox = sinon.createSandbox();

  // Stub firestore的collection方法
  const collectionStub = sandbox.stub(admin.firestore(), 'collection').callsFake((colPath) => {
    const originalCollection = admin.firestore().collection(colPath);
    // 再Stub该collection的doc方法
    const docStub = sandbox.stub(originalCollection, 'doc').callsFake((docId) => {
      const originalDocRef = originalCollection.doc(docId);
      // 对ID为"3"的文档Stub get方法
      if (docId === "3") {
        sandbox.stub(originalDocRef, 'get').rejects(new Error('Failed to fetch landing page'));
      }
      return originalDocRef;
    });
    return originalCollection;
  });
});

关键注意事项

  • 务必在afterEach中调用sandbox.restore(),避免Stub污染其他测试用例
  • 如果需要模拟多个文档的错误,只需扩展方案中的ID判断逻辑即可
  • 方案1会影响所有DocumentReference实例,需确保其他测试用例不受影响,或在测试后彻底清理Stub

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 03:29:55