LoginSignup
11
11

More than 5 years have passed since last update.

FluxをJest以外でテストする

Posted at

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.firstCallspy.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
test/stores/TodoStore.test.coffee
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
11
11
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
11
11