如何在nodejs上使用mocha对控制台输出进行单元化?

时间:2015-06-03 16:12:19

标签: node.js unit-testing automated-tests mocha sinon

考虑以下示例Javascript代码:

function privateFunction (time) {
  if (time < 12) { console.log('Good morning'); }
  if (time >= 12 && time <19) { console.log('Good afternoon'); }
  else { console.log('Good night!'); }
};

我应该如何使用mocha(也可能是sinonjs)对nodejs进行单元测试,注意到这是一个在模块内部调用的私有函数?我需要传入参数并检查函数是否正确记录到控制台。

我可以对console.warnconsole.error执行相同操作吗?

3 个答案:

答案 0 :(得分:29)

我更喜欢mocha-sinon而不是“普通”的sinon,因为它与Mocha完美融合。

示例:

var expect = require('chai').expect;
require('mocha-sinon');

// Function to test, can also be in another file and as long as it's
// being called through some public interface it should be testable.
// If it's not in any way exposed/exported, testing will be problematic.
function privateFunction (time) {
  if (time < 12) { console.log('Good morning'); }
  if (time >= 12 && time <19) { console.log('Good afternoon'); }
  else { console.log('Good night!'); }
}

describe('privateFunction()', function() {

  beforeEach(function() {
    this.sinon.stub(console, 'log');
  });

  it('should log "Good morning" for hours < 12', function() {
    privateFunction(5);
    expect( console.log.calledOnce ).to.be.true;
    expect( console.log.calledWith('Good morning') ).to.be.true;
  });

  it('should log "Good afternoon" for hours >= 12 and < 19', function() {
    privateFunction(15);
    expect( console.log.calledOnce ).to.be.true;
    expect( console.log.calledWith('Good afternoon') ).to.be.true;
  });

  it('should log "Good night!" for hours >= 19', function() {
    privateFunction(20);
    expect( console.log.calledOnce ).to.be.true;
    expect( console.log.calledWith('Good night!') ).to.be.true;
  });

});

一个潜在的问题:一些Mocha记者也使用console.log,因此存在它的测试可能不会产生任何输出。

有一种解决方法,但它并不理想,因为它会将Mocha输出与privateFunction()的输出散布在一起。如果这不是问题,请将beforeEach()替换为:

beforeEach(function() {
  var log = console.log;
  this.sinon.stub(console, 'log', function() {
    return log.apply(log, arguments);
  });
});

答案 1 :(得分:3)

忽略它是私人功能的事实,我会采取几个步骤;重构我的代码以更好地分离关注点,并将这种分离与测试双打一起使用。

  • 将所有副作用带到自己的模块中(此处的副作用是写入控制台):

    <强> out.js

    function log (message) {
      console.log(message);
    };
    
    module.exports = {log};
    

    <强> app.js

    const {log} = require('out');
    
    function greeter (time) {
      if (time < 12) {
        log('Good morning');
      }
      if (time >= 12 && time < 19) {
        log('Good afternoon');
      } else {
        log('Good night!');
      }
    };
    
    module.exports = {greeter};
    
  • 在测试时使用一些模块代理/间谍,如proxyquire来替换整个编写器:

    <强> app.spec.js

    describe('output writers', function(){
    
      const fakeOut = {
        log: sinon.spy(),
      };
    
      const app = proxyquire('./app', {
        'out': fakeOut
      });
    
      it('should log to the fake out', function(){
        app.greeter(15);
        assert(fakeOut.log.calledOnce);
      });
    });
    

答案 2 :(得分:0)

如果您的目的仅仅是测试控制台输出,我建议在方法调用中使用

代替stub / spies等。
相关问题