tim*_*tim 4 unit-testing sinon firebase sinon-chai google-cloud-functions
男人,这个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.');
});
});
Run Code Online (Sandbox Code Playgroud)
单元测试代码:
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)
})
})
})
Run Code Online (Sandbox Code Playgroud)
我用我的问题注释了上面的源代码,但我会在这里重申一下.
我如何验证传递给事务存根的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字段,它在事务中更新.通过模拟数据库,我们的单元测试检查是否正确完成了一行代码.
我希望这可以帮助您进行测试!
| 归档时间: |
|
| 查看次数: |
2489 次 |
| 最近记录: |