【问题标题】:Stub Node.js utility function called from a callback (Sinon and Agenda)从回调中调用的 Stub Node.js 实用函数(Sinon 和 Agenda)
【发布时间】:2020-05-23 00:46:22
【问题描述】:

我正在将议程用于后台作业,并且我正在尝试测试定义方法以确保 1.) 议程.define 被调用和 2.) 议程内部的一个方法被调用 (triggerSend)。

我已经包含了我用来进行此测试的四个文件:1.) 议程作业定义 2.) triggerSend 实用函数 3.) sinon 存根 4.) 实际测试。我将非常感谢您提供的任何帮助!

按原样,agenda.define 被调用了两次,我可以看到 triggerSend 的日志被调用了两次。第一个 triggerSend 显示一个作业对象,第二个 triggerSend 日志显示undefined

我想弄清楚如何准确捕获议程。使用 sinon 定义 triggerSend 被调用。

agenda/campaigns/jobs/test.js(带有agenda.define的工作):

const triggerSend = require('../../../campaign/trigger.js');

module.exports = function(agenda) {
    agenda.define('test', function(job,done){
        console.log("agenda.define called!");
        triggerSend(job)
        .then(done).catch(done);
    });
}

campaign/trigger.js 在议程中调用 triggerSend 实用函数:

module.exports = async function(job) {
    console.log("triggerSend for job: ", job);
    // Legacy procedural code
}

fixtures/stubs/index.js

const sinon = require('sinon');

module.exports = {
    DefineAgenda: function(agenda, jobMock) {
        return sinon.stub(agenda, 'define').callsFake(function(job, done) {
            /*
            *This is to call the function (job, done) callback from agenda.define,
            *it results in triggerSend being actually called (not the stub) but it
            *also results in agenda.define being called twice.
            */
            return arguments[1](jobMock, done);
        });
    },
    TriggerSend: function(triggerSend, jobMock) {
        return sinon.stub(triggerSend, 'default').callsFake(function(job) {
            console.log("triggerSend arguments: ", arguments)
            return arguments[1](jobMock);
        });
    }
}

test.test.js:

const chai = require("chai");
const expect = chai.expect;

const agenda = require('../../../modules/agenda').campaignInstance();
const triggerSend = require('../../../campaign/trigger.js');
const triggerSendObj = { default: triggerSend };

const DefineAgenda = require('../../../fixtures/stubs').DefineAgenda;
const TriggerSend = require('../../../fixtures/stubs').TriggerSend;
const jobMock = require('../../../fixtures/mocks/jobs').campaign;

const testJob = require('../../../agenda/campaigns/jobs/test.js');

describe('Campaign agenda.define', function() {
    before(function() {
        this.DefineAgendaStub = DefineAgenda(agenda, jobMock);
        this.TriggerSendStub = TriggerSend(triggerSendObj, jobMock);
    });

    it('is called', async function() {
        //call agenda job for test
        testJob(agenda);

        //assertions
        expect(agenda.define.called).to.be.true;
        expect(triggerSendObj.default.called).to.be.true;
    })
});

【问题讨论】:

    标签: node.js mocha.js chai sinon agenda


    【解决方案1】:

    捕获议程.define 很容易,但捕获 triggerSend 被调用并不容易。这需要准备。

    我是agendajs 用户,这个例子说明了我是如何做到这一点的,使用你的一段代码,我稍微修改了一下以使其更容易测试。

    对于这个测试,我使用包:mongodb-memory-server(为了让议程工作,需要 mongodb 服务器)、mongodb(作为 mongo 客户端)、agenda、chai、sinon 和 delay(需要以确保期望在附加时间之后运行)。

    目录中有3个文件:

    1. trigger.js,提供作业运行时调用的异步函数定义;
    2. test.js,提供定义“测试”作业的函数;
    3. trigger.test.js,提供测试规范来检查是否调用了议程定义,以及在“测试”作业运行时是否调用了 trigger.js 中的异步函数。
    // File: trigger.js
    module.exports = {
      send: async () => {
        console.log('Trigger Send');
        return Promise.resolve(true);
      }
    };
    
    // File: test.js
    const trigger = require('./trigger.js');
    
    module.exports = function(agenda) {
      // Define a job name: test, as async job using done.
      agenda.define('test', function(job, done) {
          trigger.send(job).then(done);
      });
    }
    
    // File trigger.test.js
    const { MongoMemoryServer } = require('mongodb-memory-server');
    const { MongoClient } = require('mongodb');
    const Agenda = require('agenda');
    const { expect } = require('chai');
    const sinon = require('sinon');
    const delay = require('delay');
    
    const testJob = require('./test.js');
    const trigger = require('./trigger.js');
    
    describe('Agenda test', function () {
      let mongoServer;
      let mongoClient;
      let sandbox;
      let agenda;
    
      before(async function () {
        mongoServer = new MongoMemoryServer();
        // Get mongo uri from memory server.
        const mongoUri = await mongoServer.getUri();
        // Get client.
        mongoClient = new MongoClient(mongoUri, {
          useUnifiedTopology: true,
        });
        // Connect to database.
        await mongoClient.connect();
        // Initiate agenda.
        agenda = new Agenda({
          mongo: mongoClient.db('agenda'),
        });
        // Initiate sandbox.
        sandbox = sinon.createSandbox();
      });
    
      after(async function () {
        await mongoClient.close();
        await mongoServer.stop();
        sandbox.restore();
      });
    
      it('define called', function () {
        const spyAgendaDefine = sandbox.spy(Agenda.prototype, 'define');
        // Define test.
        testJob(agenda);
        // Expect that spy agenda define get called.
        expect(spyAgendaDefine.calledOnce).to.equal(true);
        // To make sure that the defined job name: test.
        expect(spyAgendaDefine.args[0][0]).to.equal('test');
      });
    
      it('triggerSend run', async function () {
        const spyTriggerSend = sandbox.spy(trigger, 'send');
        // Job name test has define above.
        // Start agenda properly.
        await agenda.start();
        // Run test job now.
        await agenda.now('test');
        // Need to add next tick delay.
        await delay(5);
        // Stop agenda properly.
        await agenda.stop();
        // Expect trigger send get called once.
        expect(spyTriggerSend.calledOnce).to.equal(true);
      });
    });
    

    当我在终端使用 mocha 运行它时:

    $ npx mocha trigger.test.js 
    
    
      Agenda test
        ✓ define called
    Trigger Send
        ✓ triggerSend run
    
    
      2 passing (109ms)
    

    109ms,很快吧?在内存中启动 mongodb 服务器不会减慢您的速度。 :D

    注意事项:

    • before函数需要运行mongodb服务器,连接mongodb服务器,正确初始化议程,初始化sinon沙箱。
    • after函数需要关闭mongodb连接,关闭mongodb服务器,恢复sinon沙箱。这是为了让测试运行程序不挂起并等待超时。

    【讨论】:

      猜你喜欢
      • 2021-09-04
      • 2019-11-24
      • 1970-01-01
      • 2019-10-28
      • 2018-08-28
      • 1970-01-01
      • 1970-01-01
      • 2014-05-07
      • 2017-10-24
      相关资源
      最近更新 更多