web-dev-qa-db-ja.com

nodejsでmochaを使用してコンソール出力を単体テストする方法は?

以下の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でも同じことができますか?

26
Kemel Zaidan

私は _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;
  });

});
_

1つの潜在的な問題:一部のMochaレポーターは_console.log_も使用するため、スタブ化するテストでは出力が得られない場合があります。

回避策はありますが、Mochaの出力とprivateFunction()からの出力が点在するため、理想的でもありません。それが問題でない場合は、beforeEach()を次のように置き換えます。

_beforeEach(function() {
  var log = console.log;
  this.sinon.stub(console, 'log', function() {
    return log.apply(log, arguments);
  });
});
_
32
robertklep

それがプライベート関数であるという事実を無視して、私はいくつかのステップを踏むでしょう。懸念のより良い分離のためにコードをリファクタリングし、この分離をテストダブルで使用します。

  • 外部のすべての副作用を独自のモジュールに取り込みます(ここでの副作用はコンソールへの書き込みです)。

    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 などのモジュールproxy/spyを使用して、テスト時にアウトライター全体を置き換えます。

    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);
      });
    });
    
3
Eliran Malka

コンソール出力をテストすることが目的solelyの場合、メソッド呼び出しのスタブ/スパイなどの代わりに、次のようなものを使用することをお勧めします。

0