如何使用构造函数和依赖关系来testing无服务器的lambda函数?

如何在构造函数中存储构造函数以传递对构造对象的期望?

我正在使用无服务器,我有一个lambda函数具有依赖关系,并通过计划的事件每分钟运行。 我想专注于lambda函数的行为,所以我想我的一个testing如下 – >它从消息队列中取消消息。 testing将validation我的队列已经收到一个函数dequeueMessages – 就是这样。 这里是我的示例lambda:

module.exports = function(event, context, callback) { var queue = new Queue(); queue.dequeueMessages(params).then(messages => { var client = new DataFetcher(); return client.fetchData(messages).then(data => { var database = new Database(); return database.persist(data); }) } } 

我知道那里还有其他的依赖关系,但是我只想把重点放在获得第一个testing通过上,而我正在努力用new Queue来断言构造的对象队列调用了#dequeueMessages。 我已经探索过了 ,现在有了摩卡和柴的testing,但我不知道如何把所有的工具放在一起做这个非常简单的testing。

       

网上收集的解决方案 "如何使用构造函数和依赖关系来testing无服务器的lambda函数?"

我想推荐这篇文章 ,它涵盖了unit testingAWS lambda函数时非常重要的方面。

我采取了他们这样做的方式。

既然你只想把重点放在实现的细节上,那就很简单。 我附上了一个基于你的示例文件的工作示例,只是为了完整性做了一些调整。

lib.js

这是模仿第三方依赖的模块 – 通常在你的代码中应该是类似于AWS lib的东西等等

 class Queue{ constructor(){ } dequeueMessages(params ){ console.log('dequeueMessages()', params); const messages = []; return Promise.resolve(messages); } } class DataFetcher{ constructor(){ } fetchData(messages ){ console.log('fetchData()', messages); const data = {}; return Promise.resolve(data); } } class Database{ constructor(){ } persist(data ){ console.log('persist()', data); return Promise.resolve(); } } module.exports.Queue = Queue; module.exports.Database = Database; module.exports.DataFetcher = DataFetcher; 

lambda.js

改变了一点,以便它完成后通知它的来电者。

 'use strict'; const Queue = require('./lib').Queue; const DataFetcher = require('./lib').DataFetcher; const Database = require('./lib').Database; module.exports = function(event, context, callback) { var queue = new Queue(); var params = {}; queue.dequeueMessages(params).then(messages => { var client = new DataFetcher(); return client.fetchData(messages).then(data => { var database = new Database(); database.persist(data).then(() => { callback(null, {}); }); }); }).catch((error) => { callback(error); }); }; 

test.js

 'use strict'; const chai = require('chai'); const sinon = require('sinon'); const SinonChai = require('sinon-chai'); var sinonStubPromise = require('sinon-stub-promise'); sinonStubPromise(sinon); chai.use(SinonChai); chai.should(); const lambda = require('./lambda'); const Queue = require('./lib').Queue; const DataFetcher = require('./lib').DataFetcher; const Database = require('./lib').Database; context('Test', () => { beforeEach(() => { if (!this.sandbox) { this.sandbox = sinon.sandbox.create(); } else { this.sandbox.restore(); } }); it('should pass the test', (done) => { const event = {}; const ctx = {}; const stubQueue = sinon.stub(Queue.prototype, 'dequeueMessages') .resolves(['1', '2']); const stubDataFetcher = sinon.stub(DataFetcher.prototype, 'fetchData') .resolves({}); const stubDatabase = sinon.stub(Database.prototype, 'persist') .resolves(); lambda(event, ctx, (error, result) => { try { // all stubs should have been called // one time each stubQueue.should.have.been.calledOnce; stubDataFetcher.should.have.been.calledOnce; stubDatabase.should.have.been.calledOnce; done(); } catch (e) { done(e); } }); }); }); 

你可以做的最简单的事情就是在原型级别存储所需的方法,并相应地控制它们的行为。 在这个例子中,我们在lambda内部使用了3个感兴趣的方法,以便返回一个伪造的结果,以便按照所需的path驱动testing。

最后,由于lambda的本质是asynchronous的,所以我们强制它使用callback函数,这样我们就可以在完成时正常运行我们的断言。

以此为骨架,您可以充分利用Sinon提供的所有function,以便彻底validation您的实现逻辑。

最后但并非最不重要的,@johni共享的文章应该被用作更复杂场景的参考。