Как отключить тестовую консоль с моккой на nodejs?

Примите во внимание следующий пример кода 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), замечая, что это частная функция, называемая внутри модуля? Мне нужно передать аргумент и проверить, правильно ли функция записывает правильную информацию на консоль.

Могу ли я сделать то же самое с console.warn и console.error?

Ответ 1

Я предпочитаю mocha-sinon над "простым" синоном, потому что он хорошо сочетается с моккой.

Пример:

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

Ответ 2

игнорируя тот факт, что это частная функция, я бы сделал пару шагов; реорганизовать мой код для лучшего разделения проблем и использовать это разделение с двойными испытаниями.

  • принимать все побочные эффекты вне их собственных модулей (побочный эффект здесь записывается на консоль):

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