【问题标题】:How write tests for checking behaviour during graceful shutdown in node.js?如何编写测试以检查 node.js 中正常关闭期间的行为?
【发布时间】:2016-12-01 07:50:51
【问题描述】:

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

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 测试这段代码?

【问题讨论】:

    标签: node.js mocha.js


    【解决方案1】:

    这显然取决于您想要测试代码的范围,但这里有一个样板文件。

    一些解释:

    • 代码使用sinon 来存根两个函数:server.close()process.exit()。将它们存根意味着不是调用这些函数,而是调用“假函数”(存根),并且您可以断言 if 它被调用;
    • 我注释掉了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);
          })
    
        })
    
      })
    
    })
    

    【讨论】:

    • 这是一个非常好的测试,感谢分享。很棒的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 2013-12-18
    • 1970-01-01
    相关资源
    最近更新 更多