Testing Flux Applicationsでは、Storeをテストする際のトリックとしてJest上で以下のコードを実行している。
var mockRegister = MyDispatcher.register;
var mockRegisterInfo = mockRegister.mock;
var callsToRegister = mockRegisterInfo.calls;
var firstCall = callsToRegister[0];
var firstArgument = firstCall[0];
var callback = firstArgument;
Jestは基本全てがモックされるので、要は「Dispatcherのregister
に与えられた引数が観測できるから、Storeのcallbackを捕捉してテストしたい内容に合わせて適宜実行せよ」ということである。
この動作、SinonのSpyにも同じような実装がある。spy.firstCall
やspy.getCall
が定義されており、n度目に呼ばれた際に渡された引数を取得できる。例えば以下のコードでMyStore内部に定義したcallbackは取得できる。
register = spy require('../../src/dispatcher/AppDispatcher'), 'register'
MyStore = require '../../src/stores/MyStore'
callback = register.lastCall.args[0]
Storeは常に単一のインスタンスであることを強制されるので、テストごとに状態をリセットしないと前の状態を保持してしまう。Storeの状態を直接変えたりsetterを作るのは禁じ手なので、テストごとにrequire
が新たなStoreを返すようにする。
require
すると通常の場合結果がrequire.cache
にキャッシュされるので、require.cache
から削除することで、再度require
したとき新しいStoreが返ってくるようにできる。
delete require.cache[require.resolve '../../src/stores/MyStore']
実際に動かす
Jestで書かれたFlux TodoMVCのテストをMocha, power-assertで動くように書く。
$ npm install mocha power-assert sinon espower-coffee --save-dev
assert = require 'power-assert'
{spy} = require 'sinon'
describe 'TodoStore', ->
TodoConstants = require '../../js/constants/TodoConstants'
register = null
TodoStore = null
callback = null
actionTodoCreate =
actionType: TodoConstants.TODO_CREATE,
text: 'foo'
actionTodoDestroy =
actionType: TodoConstants.TODO_DESTROY,
id: 'replace me in test'
before ->
register = spy require('../../js/dispatcher/AppDispatcher'), 'register'
beforeEach ->
delete require.cache[require.resolve '../../js/stores/TodoStore']
TodoStore = require '../../js/stores/TodoStore'
callback = register.lastCall.args[0]
it 'creates a to-do item', ->
callback actionTodoCreate
all = do TodoStore.getAll
keys = Object.keys all
assert.equal keys.length, 1
assert.equal all[keys[0]].text, 'foo'
it 'destroys a to-do item', ->
callback actionTodoCreate
all = do TodoStore.getAll
keys = Object.keys all
assert.equal keys.length, 1
actionTodoDestroy.id = keys[0]
callback actionTodoDestroy
assert.equal all[keys[0]], undefined
$ ./node_modules/.bin/mocha --require espower-coffee/guess test/**/*.test.coffee
TodoStore
✓ creates a to-do item
✓ destroys a to-do item
2 passing (100ms)
Jest(Contextify)がsandboxを作るのよりも比較的低コストでテストができる。
$ time ./node_modules/.bin/mocha --require espower-coffee/guess test/stores/TodoStore.test.coffee
./node_modules/.bin/mocha --require espower-coffee/guess 0.69s user 0.09s system 99% cpu 0.787 total
$ time ./node_modules/.bin/jest js/stores/__tests__/TodoStore-test.js
./node_modules/.bin/jest js/stores/__tests__/TodoStore-test.js 0.42s user 0.08s system 44% cpu 1.119 total