如何编写在node.js中正常关闭期间检查行为的测试?

时间:2016-12-01 07:50:51

标签: node.js mocha

有一个我正常关闭的例子:

function stopHandler() {
  logger.info(`Stopping server on port ${settings.port} with pid ${process.pid} started`);

  server.close(() => {
    logger.info(`Server on port ${settings.port} with pid ${process.pid} stopped`);
    process.exit();
  });

  setTimeout(() => {
    logger.info(`Server on port ${settings.port} with pid ${process.pid} stop forcefully`);
    process.exit();
  }, settings.stopTimeout);
};

process.on("SIGTERM", stopHandler);
process.on("SIGINT", stopHandler);

如何使用mocha测试此代码?

1 个答案:

答案 0 :(得分:12)

这显然取决于你想要多大程度地测试你的代码,但这是一个开头的样板。

一些解释:

  • 该代码使用sinon来存根两个函数:server.close()process.exit()。对它们进行拼写意味着不是调用那些函数,而是伪造函数" (存根)被调用,你可以断言如果它被调用;
  • 我评论了SIGINT测试,因为我发现mocha使用该信号来中止测试运行器。但是,由于SIGTERMSIGINT都使用完全相同的处理程序,因此应该没问题;
  • 信号传递是异步的,这意味着测试也必须是异步的。我添加了一次"一次"待测信号的信号处理程序,当进程发送信号时被调用;此时,应该调用stopHandler,进行断言,最后调用done回调告诉Mocha测试已完成;

代码:

const sinon = require('sinon');

// Load the module to test. This assumes it exports (at least)
// `server` and `settings`, because the test needs them.
let { server, settings } = require('./your-module');

// Don't call the stopHandler when exiting the test.
after(() => {
  process.removeAllListeners('SIGTERM');
  process.removeAllListeners('SIGINT');
})

describe('Signal handling', () => {
  [ 'SIGTERM' /*, 'SIGINT' */ ].forEach(SIGNAL => {

    describe(`${ SIGNAL }`, () => {
      let sandbox, closeStub, exitStub;

      beforeEach(() => {
        sandbox   = sinon.sandbox.create({ useFakeTimers : true });
        closeStub = sandbox.stub(server, 'close');
        exitStub  = sandbox.stub(process, 'exit');
      })

      afterEach(() => {
        sandbox.restore();
      })

      it(`should call 'server.close()' when receiving a ${ SIGNAL }`, done => {
        process.once(SIGNAL, () => {
          sinon.assert.calledOnce(closeStub);
          done();
        });
        process.kill(process.pid, SIGNAL);
      })

      it(`should call 'process.exit()' after ${ settings.stopTimeout } seconds when receiving a ${ SIGNAL }`, done => {
        process.once(SIGNAL, () => {
          // It shouldn't have called `process.exit()` right after the signal was sent.
          sinon.assert.notCalled(exitStub);

          // Advance the clock to a bit after the timeout.
          sandbox.clock.tick(settings.stopTimeout + 10);

          // At this point, the timeout handler should have triggered, and
          // `process.exit()` should have been called.
          sinon.assert.calledOnce(exitStub);

          // Done.
          done();
        });
        process.kill(process.pid, SIGNAL);
      })

    })

  })

})