シングルトン(singleton.js)。
module.exports = { value: 0 };
その値をインクリメントするやつ(incr.js)。
var singleton = require('./singleton.js'); module.exports = function incr() { singleton.value++; };
incr()
を呼んだら値が増えますというテストを2つ記述。
var assert = require('assert'); var incr = require('../src/incr.js'); describe('a', function() { it('1', function() { var singleton = require('../src/singleton.js'); incr(); assert(singleton.value === 1); }); it('2', function() { var singleton = require('../src/singleton.js'); var incr = require('../src/incr.js'); incr(); assert(singleton.value === 1); }); });
なんと同じテストなのに2つ目だけ失敗!ガーン!
改良?
シングルトンだからそりゃそうだよねと思って、調べてみたらrequire
にキャッシュされているモジュールを削除できるらしい。というわけで、使い終わったシングルトンを削除っと。
var assert = require('assert'); var incr = require('../src/incr.js'); describe('a', function() { it('1', function() { var singleton = require('../src/singleton.js'); incr(); assert(singleton.value === 1); delete require.cache[require.resolve('../src/singleton.js')];//追加 }); it('2', function() { var singleton = require('../src/singleton.js'); incr(); assert(singleton.value === 1); }); });
また失敗!ズコー!
ちなみにこの時のsingleton.value
は0
。実はincr
が参照しているのは最初にrequire
したシングルトンなので、消したつもりで消えていなかった。
これも駄目
内部でrequire
してみたけど、incr
自体がキャッシュされているのでこれも駄目。
var assert = require('assert'); describe('a', function() { it('1', function() { var singleton = require('../src/singleton.js'); var incr = require('../src/incr.js');//移動 incr(); assert(singleton.value === 1); delete require.cache[require.resolve('../src/singleton.js')]; }); it('2', function() { var singleton = require('../src/singleton.js'); var incr = require('../src/incr.js');//移動 incr(); assert(singleton.value === 1); }); });
直った
最終的にこうすると直る。
var assert = require('assert'); describe('a', function() { it('1', function() { var singleton = require('../src/singleton.js'); var incr = require('../src/incr.js'); incr(); assert(singleton.value === 1); delete require.cache[require.resolve('../src/singleton.js')]; delete require.cache[require.resolve('../src/incr.js')];//追加 }); it('2', function() { var singleton = require('../src/singleton.js'); var incr = require('../src/incr.js'); incr(); assert(singleton.value === 1); }); });
より一般的には、require.cacheのkeyで回して全部消す。中には初期化がクソ重たいモジュールがあるかもしれないが、そんなことを気にしてはいけない。
というわけで、この例くらい単純ならいいんだけど、思わぬところに思わぬ依存があって死ぬので確実に全モジュールを削除 & 毎回関数内でrequireを徹底する必要があるという話。最近Fluxなアプリがシングルトンモジュールをせっせと作っていて、こういうテストをするためにJestに依存するの嫌だなーと思っている。
あと、効果音がちょっと古い。