Node.js
test
mocha
Sinon.JS
stub

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

More than 1 year has passed since last update.

テスト対象関数で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

});


参考

https://stackoverflow.com/questions/6997459/how-to-stub-require-expect-calls-to-the-root-function-of-a-module