テストフレームワーク mocha

JavaScript Advent Calendar 2011 (Node.js/WebSocketsコース)3日目のhokacchaです。Node.jsのテストフレームワーク、mochaについて書きます。

mochaはTJが新しく作り始めているテストフレームワークです。ドキュメントを見ればできることは大体書いてありますので、ドキュメントを元にどういうことができるのかを解説していきます。現時点でのバージョンは0.2.0です。
http://visionmedia.github.com/mocha/

shouldについて

まずmochaでどういうことができるかの前にshouldについて解説しておきます。mochaのドキュメントには特に説明もなくshouldが使われていて、shouldでどういうことができるかわかってないと、ドキュメントを読んだときにmochaの機能なのかshouldの機能なのかがわかりにくくなるからです。
https://github.com/visionmedia/should.js

shouldは一言でいうとassertの拡張です。なので基本的にはテストフレームワークと組み合わせて使うことになります。例えばこんな書き方ができるようになります。

var should = require('should');
var hoge = 'fuga';
var point = {
    x: 10,
    y: 20
};

hoge.should.equal('fuga');
point.should.have.property('x', 10);
point.should.have.property('y', 20);
point.should.not.have.property('z');

見てわかるとおり、shouldはObject.prototypeを拡張します。

またrequire('should')で返ってくるオブジェクトはassertに一部の機能を追加したものなので、このように書くことも可能です。

var should = require('should');
var hoge = 'fuga';
var point = {
    x: 10,
    y: 20
};

should.equal(hoge, 'fuga');
should.equal(point.x, 10);
should.equal(point.y, 20);
should.not.exist(point.z);

これがshouldの基本的な機能です。他にも色々メソッドとかがあるので詳しくはドキュメントを読んでみるといいと思います。

mochaの概要

ここから本題。mochaについての話しです。mocha自体にはアサーションの機能はなく、標準のassertやshouldなどを使ってうまいことテストを書けて、結果の出力とかも色々やってくれるのがmochaの役割です。まずインストールしましょう

$ npm install -g mocha

インストールしたらmochaコマンドが使えるようになるので早速テストを書いてみます。

// test1.js
var assert = require('assert');

describe('mochaのテスト', function() {
  it('1 + 1は2になること', function() {
    assert.equal(1 + 1, 2);
  });
});
$ mocha test1.js

  mochaのテスト
    - 1 + 1は2になること  


   - tests complete (3ms)

実行できました。describeとかit辺りがmochaの機能です。テスト自体はassertで行っています。

非同期のテストも当然サポートしています。

// test2.js
var assert = require('assert');

describe('mochaのテスト', function() {
  it('1秒待つこと', function(done) {
    setTimeout(function() {
      assert.ok(true);
      done();
    }, 1000);
  });
  it('1 + 1は2になること', function() {
    assert.equal(1 + 1, 2);
  });
});
$ mocha test2.js

  mochaのテスト
    - 1秒待つこと (1002ms)
    - 1 + 1は2になること  


 - 2 tests complete (1006ms)

doneが呼ばれるまで次のテストを待ちます。

選べるインターフェース

mochaの特徴の一つとして、インターフェースにTDD、BDD、exportsを選べるというのがあります。さっきのコードをTDDインターフェースで書いた場合こうなります。

// test3.js
var assert = require('assert');

suite('mochaのテスト', function() {
  test('1 + 1は2になること', function() {
    assert.equal(1 + 1, 2);
  });
});

見てわかる通り、describeがsuite、itがtestとなっているだけです。実際に内部のコードを見ても名前が違うだけでやってることは全く同じです。これを実行するにはコマンドオプションでインターフェースにtddを指定する必要があります。

$ mocha --ui tdd test3.js

exportsもほとんど同じです。

// test4.js
var assert = require('assert');

module.exports = {
  'mochaのテスト': {
    '1 + 1は2になること': function() {
      assert.equal(1 + 1, 2);
    }
  }
};

実行時のインターフェースはexportsを指定します。

$ mocha --ui exports test4.js

デフォルトのインターフェースはBDDなので何も指定しない場合はBDDとなります。

before、afterフック

テストの最初や最後に処理を挟みたいことはよくあります。mochaではこんな感じで書きます。

var assert = require('assert');

describe('mochaのテスト', function() {
  before(function(done) {
    // テストが始まる前の処理
    done();
  });

  after(function(done) {
    // テストが終わった後の処理
    done();
  });

  beforeEach(function(done) {
    // 各テストごとの始まる前の処理
    done();
  });

  afterEach(function(done) {
    // 各テストごとの終わった後の処理
    done();
  });

  it('1 + 1は2になること', function() {
    assert.equal(1 + 1, 2);
  });
});

特にdescribeごとのフック(before, after)とitごとのフック(beforeEach, afterEach)が分かれているのはかなりいいですね。

また、TDDインターフェースでは、before→suiteSetup、after→suiteTeardown、beforeEach→setup、afterEach→teardownとなるみたいです(suiteSetupとsuiteTeardownはアンドキュメントだけど単なる書き忘れな気がする)

様々なレポーター

mochaではレポーターもデフォルトで様々なものが用意されています。レポーターってのは出力形式のことです。コマンドラインオプションで様々なレポーターを指定できます。

$ mocha --reporter dot test.js
dot

デフォルトはdotというのになっています。テストひとつひとつをドットで表していて、テスト失敗したらドットが赤くなったりとかします。


spec

specの形式で出力します。個人的には一番見やすい気がします。


tap

tap形式で出力します。id:sugyanも安心ですね。


landing

テストの経過を飛行機が進んでいく様子で表しています。シャレでいれたみたいです。


list

シンプルなリスト形式で出力してくれます。


progress

プログレスバー的なのでテストの経過を表示します。


json

jsonで出力します。テストの結果を使って何かするAPIとかに使うのにはよさげです。


json-stream

各テストが終わるごとにJSONで結果を出力します。


doc

HTMLで出力します。ドキュメントに載せるときとかに使うのかな。


html

クライアントサイドで使う用みたいです。コマンドラインでやったら$がないって言われました。


その他の便利機能

mochaはその他にも便利な機能が色々あります。

require
  • rオプションでデフォルトでrequireするモジュールを指定できます。
$ mocha -r should test.js

ただ、例えばこれだとshouldをrequireはするけど、

require('should');

しただけになります。

shouldはObject.prototypeを拡張するので、その拡張した機能は使えるんですけど、require('should')で返ってくるオブジェクトを使うことができません。should自体をこんな感じで使いたいこともあるので、結局ファイルごとに書いたほうがいい気もします。

var should = require('should');
should.not.exist(err);
ストファイルの省略

mochaはテストの対象ファイルの指定を省略するとデフォルトではtest/*.jsを探してテストします。なのでそのようなディレクトリ構成になっていればこれだけでテストできます。

$ mocha
閾値の設定

mochaはテストにかかる時間を計測してくれて、設定された閾値より時間がかかったテストを警告してくれます。レポーターをデフォルト(dot)にしてる場合だとドットが黄色くなるのが警告です。あとspceレポーターとかで時間のところが赤くなってるのもこれです。この閾値のデフォルトは75msで、sオプションで指定できます。

$ mocha -s 1000 test.js
タイムアウトの設定

tオプションはタイムアウト値を設定します。デフォルトは1000msです。

$ mocha -t 10000 test.js
grep

gオプションでitやdescribeで設定したテキストをgrepしてマッチしたテストだけ実行してくれます。

$ mocha -g FizzBuzz test.js
mocha.opts

mochaには様々なオプションがあっていちいち指定するのが面倒な場合、test/mocha.optsというファイルに設定を書いておけば自動で設定を読んでくれるという便利機能があります。

mocha.opts.はこんな感じで書きます。

--ui bdd
--reporter spec
--timeout 5000
後で書く

実際にテストはまだ書かないけど後で書く予定のものを書いておくことができます。

it('後で書くよ');

これだけです。出力結果の色も変えてくれるのでわかりやすいです。


クライアントサイドサポート

mochaはクライアントサイドでの実行もサポートしています。が、これについてはフレームワークコースのほうで書こうと思います。こうご期待。