簡體   English   中英

單元測試Firebase的雲功能:使用sinon.js測試/模擬`transaction`s的“正確方法”是什么

[英]Unit testing Cloud Functions for Firebase: what's the “right way” to test/mock `transaction`s with sinon.js

男人,這個firebase單元測試真的踢我的屁股。

我已經閱讀了文檔並閱讀了他們提供的示例,並且已經對我的一些基本的Firebase功能單元進行了測試,但是我一直遇到問題,我不知道如何驗證transactionUpdated函數是否傳遞refs .transaction正確地更新current對象。

我的掙扎可能最好用他們的child-count示例代碼和我在編寫單元測試時做出的不良嘗試來說明。

假設我想要進行單元測試的函數執行以下操作(直接從上面的鏈接中獲取):

// 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回調將獲取我的startingValue並將其變為expectedValue ,然后允許我觀察該更改並斷言它發生了。

這可能是一個非常簡單的問題,有一個明顯的解決方案,但我對測試JS代碼非常陌生,所有內容都必須存根,所以這是一個學習曲線......任何幫助都是值得贊賞的。

我同意Firebase生態系統中的單元測試並不像我們希望的那樣簡單。 團隊意識到這一點,我們正努力讓事情變得更好! 幸運的是,現在一些很好的方法可以幫到你!

我建議看一下我們剛剛發布的Cloud Functions演示 在該示例中,我們使用TypeScript,但這也都在JavaScript中工作。

src目錄中你會注意到我們已經將邏輯分成三個文件: index.ts有入口邏輯, saythat.ts有我們的主要業務邏輯, db.ts是圍繞Firebase的瘦抽象層實時數據庫。 我們單位測試只說saythat.ts ; 我們故意保留index.tsdb.ts非常簡單。

spec目錄中我們有單元測試; 看看index.spec.ts 您正在尋找的技巧:我們使用 mock-require模擬整個src/db.ts文件並將其替換為spec/fake-db.ts 我們現在將執行的操作存儲在內存中,而不是寫入真實數據庫,我們的單元測試可以檢查它們看起來是否正確。 一個具體的例子是我們的score字段,它在事務中更新 通過模擬數據庫,我們的單元測試檢查是否正確完成了一行代碼

我希望這可以幫助您進行測試!

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM