1

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

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

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

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

议程/campaigns/jobs/test.js(带有议程.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
}

固定装置/存根/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;
    })
});

4

1 回答 1

1

捕获agenda.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

笔记:

  • 函数需要运行 mongodb 服务器之前,连接到 mongodb 服务器,正确初始化议程,并初始化 sinon 沙箱。
  • after函数需要关闭mongodb连接,关闭mongodb服务器,恢复sinon沙箱。这是为了让测试运行器不要挂起并等待超时。
于 2020-10-25T02:51:14.643 回答