【问题标题】:cloud function unit test mock new document ID云功能单元测试模拟新文档ID
【发布时间】:2021-12-31 17:52:36
【问题描述】:

对于 Firestore 云函数 TypeScript 单元测试,我想模拟 doc().id,但 不是 doc('path')。我该怎么做?

admin.firestore().collection('posts').doc().id // I only want to mock this one

admin.firestore().collection('posts').doc('1')

我尝试在 sinon 中执行以下操作。但它在sinon/proxy-invoke.js:50:47 处陷入无限循环:

const collection = admin.firestore().collection('posts');
sinon.stub(collection. 'doc').callsFake(path => 
   path === undefined ? mock : collection.doc(path)
);
sinon.stub(admin.firestore(), 'collection')
  .callThrough()
  .withArgs('posts')
  .returns(collection)

我还尝试了以下方法。但是doc(documentPath: string) 方法似乎也被淘汰了:

sinon.stub(collection, 'doc')
  //@ts-ignore
  .withArgs()
  .returns(mock)

如果有解决方法,我愿意使用其他模拟库。

【问题讨论】:

    标签: typescript google-cloud-firestore google-cloud-functions sinon


    【解决方案1】:

    你会得到一个无限循环,因为你递归地调用了存根方法:

    sinon.stub(collection, 'doc').callsFake(path => 
       path === undefined ? mock : collection.doc(path) // <- this calls the stub again
    );
    

    首先,您需要从要存根的对象中提取原始的 doc 方法。您还必须使用传统的function 语法,以便将this 正确传递给假回调(您还应该将其传递给您调用的任何其他函数)。虽然这个doc 函数只接受一个路径参数,但您应该养成使用rest 参数的习惯,以确保您正在处理所有参数。

    // store the raw function (make sure this only happens
    // once as you don't want to stash a stubbed function)
    const _originalDoc = collection.doc;
    
    sinon.stub(collection, 'doc')
      .callsFake(function (...args) { // important! `function` not arrow function
        // In this function, `this` is an instance of CollectionReference
        return args.length = 0 || args[0] === undefined // don't forget the return
          ? mock.call(this)                // call the mocked function
          : _originalDoc.apply(this, args) // call the original with the original arguments
      });
    

    如果您的 mock 还调用 collection.doc(),请确保调用原始函数,而不是存根函数(除非有意)。

    【讨论】:

    • 非常感谢!这完美地工作。我不得不稍微修改一下:sinon.stub(collection, 'doc').callsFake(function (this: CollectionReference, ...args) { return args[0] === undefined ? (({ id: mockID } as unknown) as DocumentReference) : // eslint-disable-next-line no-invalid-this originalDoc.apply(this, args); });
    • @JackGuo 为什么不originalDoc.apply(this, args[0] === undefined ? [mockID] : args);?它具有相同的效果,但您将获得完整的文档引用对象(如果您最终使用了该对象的其余部分)。
    • 好主意。谢谢!
    猜你喜欢
    • 2021-10-25
    • 2021-10-13
    • 2016-01-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    相关资源
    最近更新 更多