LoginSignup
3
2

More than 5 years have passed since last update.

Node.jsで単体testを書く際に,モジュールをstubに置き換える

Posted at

テスト対象関数でrequire()が使われていて,どうにかして置き換えたい時があります

本来ならtestし易いように関数の構成を変更してstubを使えばいいと思いますが,
諸事情あって中のソースは変更しないでテストをする ということをしました.

方法としてはrequireをフックする ということをします

書いたコード


var moduleStubs = {};
var originalJsLoader = require.extensions['.js'];

var stubOnModule = function(module) {
  var path          = require.resolve(module);
  var stub           = sinon.stub();
  moduleStubs[path] = stub;
  delete require.cache[path];
  return stub;
};

require.extensions['.js'] = function (obj, path) {
  if (moduleStubs[path])
    obj.exports = moduleStubs[path];
  else
    return originalJsLoader(obj, path);
};

afterEach(function() {
  for (var path in moduleStubs) {
    delete moduleStubs[path];
  }
});



requireモジュールの中身にあまり詳しくないですが,どうやらrequire.cache[path]
キャッシュがあるようなのでそれを削除し,
requireでjsファイルが呼ばれたらキャッシュしてあったstubを返すようにしています

afterEachに関してはmochaでテスト完了後に毎回stubを直す処理を書いています,.

使い方

stubOnModule(“ws”); とテストの最初にかけば,その後呼ばれるrequire(‘ws’)はstubに置き換わります.

あくまでstubへの置き換えだけなので,new や 下位pathへのアクセスをされるとプロパティがなくてエラーになります


it('test', function(){
  stubOnModule("module");

  var m = require("module"); //return stub

  var instance = new m(); // OK
  var value = m.b; // ok

  m.a(); // error : m.a is not a function
  var value = m.c.d; // error : Cannot read property 'd' of undefined
  var instance2 = new m.A({}); // error : ws.Server is not a constructor

});


その場合は,一つ一つstubにしてあげましょう


it('test', function(){
  var stub = stubOnModule("module");
  stub.a = sinon.stub();
  stub.c = sinon.stub();
  stub.c.d = sinon.stub();
  stub.A = sinon.stub();

  var m = require("module"); //return stub


  m.a(); // error : m.a is not a function
  var value = m.c.d; // error : Cannot read property 'd' of undefined
  var instance2 = new m.A({}); // error : m.A is not a constructor

});


参考

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2