[英]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.ts
和db.ts
非常簡單。
在spec
目錄中我們有單元測試; 看看index.spec.ts
。 您正在尋找的技巧:我們使用 mock-require
模擬整個src/db.ts
文件並將其替換為spec/fake-db.ts
。 我們現在將執行的操作存儲在內存中,而不是寫入真實數據庫,我們的單元測試可以檢查它們看起來是否正確。 一個具體的例子是我們的score
字段,它在事務中更新 。 通過模擬數據庫,我們的單元測試檢查是否正確完成了一行代碼 。
我希望這可以幫助您進行測試!
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.