如何在node.js的正常closures过程中编写testing来检查行为?

有一个我的优雅关机的例子:

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); 

我怎样才能用摩卡testing这个代码?

这显然取决于你想要testing你的代码的广泛程度,但是这是一个开始的样板。

一些解释:

  • 代码使用sinon来存储两个函数: server.close()process.exit() 。 对它们进行存根意味着不是调用这些函数,而是调用一个“伪函数”(存根),并且可以断言它是否被调用;
  • 我注意到了SIGINTtesting,因为我发现mocha使用这个信号来中止testing运行。 但是,由于SIGTERMSIGINT使用完全相同的处理程序,所以应该没关系;
  • 信号传递是asynchronous的,这意味着testing也必须是asynchronous的。 我为被测信号添加了“一次”信号处理程序,当进程发送信号时被调用; 在这一点上, stopHandler应该已经被调用,做出你的断言,并在最后调用donecallback告诉Mochatesting已经完成;

代码:

 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); }) }) }) })