mocha+chai+sinsonでテストを書く為に必要な最低限の知識

まとめ

  • Mochaではrspecっぽい感じにテストが書ける
  • ただし、done()を呼ぶ必要がある等、細かい部分に差異がある
  • sinonにはいろいろ便利機能がある

Mochaの使い方

coffeescriptを前提にしています。

テストの書き方

Mochaのテストは以下のように、itにテスト内容を書いた関数を渡し、
そのitを呼び出す関数をdescribeに渡すしようです。

describe "test root", ->
      it "name", (done) ->
        assert.equal getUserName, "user"
        done()

ただし、it関数では必ずdone()を呼び出す必要があります。
これを呼ばない場合は終了を待ち続け、
一定時間後にタイムアウトしてテストが失敗した扱いになります。

beforeの使い方

rspecのbeforeにあたるものは、beforeEachになります。
なお、変数を他のブロックに渡したい場合、
以下のようにdescribeの中に変数名を書いておいて、
beforeEachのなかで設定する必要があるみたいです。
参考

describe "test", ->
  room_name = undefined


  beforeEach (done) ->
    room_name = "test_room"

    done()

  describe "functions", ->
      it "executeNoteShow", (done) ->
        assert.equal getRoomName(room_name), room_name
        done()

pendingテストの作り方

テストの用意はしたけど、とりあえずpendingにしておきたい場合は二通りの方法があります。

  describe "functions", ->
      it "pending test" // 関数を渡さない場合


      // it.skipの場合、引数を渡しても実行されずにスキップする
      it.skip "pending test 2", ->
          done()

外部ファイル読み込み

test.coffeeで

class Test
  なんかいろいろ
module.exports.Test = Test

と、クラスを宣言し、module.exportsに代入します。 その後、使いたいファイル側で

Test = require('../src/test.coffee').Test

と書くと、以降Testでそのクラスが呼び出せます。

#chaiの使い方

assertを使う

前述のテストではassertを使っていますが、Mochaにはassertは入っていないため、
別ライブラリのchaiを読み込む必要があります。

global.assert = require("chai").assert

これで、 assert.equalや assert.notEqualが使えます。

sinonの使い方

mockやstubを使う

Mochaにはmockやstubの為の物は含まれていないので、
今度はsinonを読み込む必要があります。

global.sinon = require('simon')

使い方は以下の通りです

    // robot.brainがstubになる
    robot = new Object()
    robot.brain = sinon.stub()


    // hubot_note.executeNoteShowを置き換え
    // hubot_note.executeMessage実行時に
    // "test", null, nullの引数で一回だけ実行されたかをチェックする

    spy = sinon.spy(hubot_note, "executeNoteShow")
    spy.withArgs("test", null, null)
    response = hubot_note.executeMessage(room_name, "hubot note show")
    assert.ok spy.withArgs("test", null, null).calledOnce

時間変更の仕方

new Date()などによって日付がちゃんと設定されたかどうかを確認したい場合、
グローバルなDate()部分を置き換える必要があります。

…というのはよくあることなので、sinon側で既に用意されています。

@clock = sinon.useFakeTimers(0,
  "setTimeout", "clearTimeout",
  "setInterval", "clearInterval", "Date")`

これで、以降のDateコマンドは第一引数で指定した0(1970年1月1日0時0分0秒)を必ず返すようになるため、
この時間かどうかをチェックすれば大丈夫です。
また、以下のように戻り値のオブジェクトのtickメソッドにより、
指定したミリ秒だけ時間を進めることもできます。
@clock.tick(3600000)

sinonのその他の機能

sinonに関しては他にもいろいろ有用なものがあります。
ちょっと古いですが、以下のmixiさんのブログ記事は参考になると思います。

http://alpha.mixi.co.jp/2011/10798/