【问题标题】:Unit testing Cloud Functions for Firebase: what's the "right way" to test/mock `transaction`s with sinon.jsFirebase 的云功能单元测试:用 sinon.js 测试/模拟“事务”的“正确方法”是什么
【发布时间】:2017-05-18 18:39:57
【问题描述】:

伙计,这个 firebase 单元测试真的让我大吃一惊。

我已经浏览了the documentation 并阅读了他们提供的示例,并且已经对我的一些更基本的 Firebase 功能进行了单元测试,但我一直遇到一些问题,我不确定如何验证传递给引用 .transactiontransactionUpdated 函数正在正确更新 current 对象。

他们的child-count sample code 和我为它编写单元测试的糟糕尝试可能最能说明我的挣扎。

假设我要进行单元测试的函数执行以下操作(直接取自上面的链接):

// count.js
exports.countlikechange = functions.database.ref('/posts/{postid}/likes/{likeid}').onWrite(event => {
      const collectionRef = event.data.ref.parent;
      const countRef = collectionRef.parent.child('likes_count');

      // ANNOTATION: I want to verify the `current` value is incremented
      return countRef.transaction(current => {
        if (event.data.exists() && !event.data.previous.exists()) {
          return (current || 0) + 1;
        }
        else if (!event.data.exists() && event.data.previous.exists()) {
          return (current || 0) - 1;
        }
      }).then(() => {
        console.log('Counter updated.');
      });
    });

单元测试代码:

const chai = require('chai');
const chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);
const assert = chai.assert;
const sinon = require('sinon');

describe('Cloud Functions', () => {
  let myFunctions, functions;

  before(() => {
    functions = require('firebase-functions');
    myFunctions = require('../count.js');
  });

  describe('countlikechange', () => {
    it('should increase /posts/{postid}/likes/likes_count', () => {
      const event = {
        // DeltaSnapshot(app: firebase.app.App, adminApp: firebase.app.App, data: any, delta: any, path?: string);
        data: new functions.database.DeltaSnapshot(null, null, null, true)
      }

      const startingValue = 11
      const expectedValue = 12

      // Below code is misunderstood piece.  How do I pass along `startingValue` to the callback param of transaction
      // in the `countlikechange` function, and spy on the return value to assert that it is equal to `expectedValue`?
      // `yield` is almost definitely not the right thing to do, but I'm not quite sure where to go.
      // How can I go about "spying" on the result of a stub,
      // since the stub replaces the original function?
      // I suspect that `sinon.spy()` has something to do with the answer, but when I try to pass along `sinon.spy()` as the yields arg, i get errors and the `spy.firstCall` is always null. 
      const transactionStub = sinon.stub().yields(startingValue).returns(Promise.resolve(true))

      const childStub = sinon.stub().withArgs('likes_count').returns({
        transaction: transactionStub
      })
      const refStub = sinon.stub().returns({ parent: { child: childStub }})

      Object.defineProperty(event.data, 'ref', { get: refStub })

      assert.eventually.equals(myFunctions.countlikechange(event), true)
    })
  })
})

我用我的问题注释了上面的源代码,但我会在这里重申一下。

我如何验证传递给事务存根的transactionUpdate callback 是否会采用我的startingValue 并将其变异为expectedValue,然后让我观察该更改并断言它发生了。

这可能是一个非常简单的问题,但有一个明显的解决方案,但我对测试 JS 代码非常陌生,所有内容都必须被存根,所以它有点学习曲线......感谢任何帮助。

【问题讨论】:

    标签: unit-testing firebase sinon google-cloud-functions sinon-chai


    【解决方案1】:

    我同意 Firebase 生态系统中的单元测试并不像我们希望的那样简单。团队意识到了这一点,我们正在努力让事情变得更好!幸运的是, 现在有一些不错的方法可供您使用!

    我建议看看我们刚刚发布的this Cloud Functions demo。在该示例中,我们使用 TypeScript,但这也适用于 JavaScript。

    src 目录中,您会注意到我们已将逻辑拆分为三个文件:index.ts 具有入口逻辑,saythat.ts 具有我们的主要业务逻辑,db.ts 是一个瘦的Firebase 实时数据库周围的抽象层。我们只进行单元测试saythat.ts;我们故意让index.tsdb.ts 保持简单。

    spec 目录中我们有单元测试;看看index.spec.ts。您正在寻找的技巧:我们usemock-require 模拟出整个src/db.ts 文件并将其替换为spec/fake-db.ts。我们现在不是写入真实的数据库,而是将我们执行的操作存储在内存中,我们的单元测试可以检查它们看起来是否正确。一个具体的例子是我们的score 字段,即updated in a transaction。通过mocking 数据库,我们检查是否正确完成的单元测试是a single line of code

    希望对您的测试有所帮助!

    【讨论】:

    • 太棒了!感谢您的资源和回复。除了测试之外,Cloud Functions 产品给我留下了非常深刻的印象,非常强大的东西 - 文档通常也很好,只是缺少测试部门。祝您和您的团队工作顺利。
    • 谢谢蒂姆!如果您遇到更多问题,请告诉我们。我们渴望让一切都变得很棒。 :)
    • @Robert-JanHuijsman 我也对 firebase 印象深刻,我在过去 3 天里一直在研究它,因为我认为这将是我和其他许多人的后端的未来。我希望你拥有的一件事是路线图。这样我们就可以知道您在做什么。
    • 很高兴听到!已注意到您对路线图的要求!同时,我建议注册我们的 Alpha 计划 - 这会让您先睹为快,了解我们正在开发的许多很酷的技术:firebase.google.com/alpha
    猜你喜欢
    • 2021-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-10
    • 1970-01-01
    • 2012-05-04
    相关资源
    最近更新 更多