gist

2012年1月11日水曜日

mochaでNodeをユニットテストしてみる

Nodeのユニットテストですが、mochaがイイみたいな情報がMLで流れていたので試しに使ってみます。

mochaをインストールする

mochaでは、アサーションにshould.jsやexpect.js、chal、node標準のassertモジュールなどを選べるそうです。ここでは should.js を使いますので同時にインストールします。

$ mkdir mocha_example
$ cd mocha_example/
$ npm install mocha should
should@0.4.2 /usr/local/lib/node_modules/should 
mocha@0.9.0 /usr/local/lib/node_modules/mocha 
 |- growl@1.4.1
 |- debug@0.1.0
 |- commander@0.5.1
 |- say@0.5.0

testディレクトリを用意して、その中にテストコードを作成します。mochaはtestディレクトリ内のすべてのjsファイルをテストコードとして実行します。

$ mkdir test
$ vim test/user.test.js

user.test.js

var should = require('should');
var user = require('../lib/user.js');

describe('User', function() {
    describe('#createUser', function() {
        it('mikuはnullではありません', function() {
            var miku = new user.createUser('Miku');
            should.exist(miku);
        }); 
    }); 
});

mochaを実行してみます。

$ node_modules/mocha/bin/mocha 

node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: Cannot find module '../lib/user.js'
    at Function._resolveFilename (module.js:334:11)
    at Function._load (module.js:279:25)
    at Module.require (module.js:357:17)
    at require (module.js:368:17)
    at Object.<anonymous> (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/test/user.test.js:2:12)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Module.require (module.js:357:17)
    at require (module.js:368:17)
    at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/bin/_mocha:226:27
    at Array.forEach (native)
    at load (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/bin/_mocha:223:9)
    at Object.<anonymous> (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/bin/_mocha:214:1)
    at Module._compile (module.js:432:26)
    at Object..js (module.js:450:10)
    at Module.load (module.js:351:31)
    at Function._load (module.js:310:12)
    at Array.0 (module.js:470:10)
    at EventEmitter._tickCallback (node.js:192:40)

モジュールがありませんのエラーが表示されます。

モジュールを作成します。ひとまずファイルだけ作成します。

$ mkdir lib
$ touch lib/user.js

mochaを実行します。

$ node_modules/mocha/bin/mocha 

  .

  ✔  1 of 1 tests failed:

  0) Userクラスのテスト userオブジェクトの作成テスト mikuはnullではありません:
     TypeError: undefined is not a function
      at Test.fn (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/test/user.test.js:7:24)
      at Test.run (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runnable.js:153:32)
      at Runner.runTest (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:271:10)
      at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:312:12
      at next (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:199:14)
      at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:208:7
      at next (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:157:23)
      at Array.0 (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:176:5)
      at EventEmitter._tickCallback (node.js:192:40)

mochaが起動し、Userオブジェクトがありません。のエラーに変わっています。

lib/user.jsを編集します。まずオブジェクトを作ります。

lib/user.js

exports.createUser = createUser;
function createUser(name) {

}

mochaを実行します。

$ node_modules/mocha/bin/mocha 

  .

   ✔ 1 tests complete (1ms)


グリーンに変わりました。テストを追加します。名前を取得できるようにしてみます。

user.test.js

var should = require('should');
var user = require('../lib/user.js');

describe('User', function() {
    describe('#createUser', function() {
        it('mikuはnullではありません', function() {
            var miku = new user.createUser('Miku');
            should.exist(miku);
        }); 
        // 追加
        it('miku.nameはMikuになります', function() {
            var miku = new user.createUser('Miku');
            miku.should.have.property('name','Miku');
        }); 
    }); 
});

mocha実行。レッドです。

$ node_modules/mocha/bin/mocha 

  ..

  ✔  1 of 2 tests failed:

  0) User #createUser miku.nameはMikuになります:
     AssertionError: expected {} to have a property 'name'
      at Object.property (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/should/lib/should.js:440:12)
      at Test.fn (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/test/user.test.js:12:30)
      at Test.run (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runnable.js:153:32)
      at Runner.runTest (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:271:10)
      at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:312:12
      at next (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:199:14)
      at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:208:7
      at next (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:157:23)
      at Array.0 (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:176:5)
      at EventEmitter._tickCallback (node.js:192:40)


user.jsを修正します。nameプロパティにMikuを設定して返すようにします。

user.js

exports.createUser = createUser;
function createUser(name) {
    return {name:'Miku'};
}

mocha実行。グリーンです。

$ node_modules/mocha/bin/mocha 

  ..

  ✔  2 tests complete (2ms)

これだとMikuしか返ってきませんので、user.test.jsにテストを追加します。

user.test.js

var should = require('should');
var user = require('../lib/user.js');

describe('User', function() {
    describe('#createUser', function() {
        it('mikuはnullではありません', function() {
            var miku = new user.createUser('Miku');
            should.exist(miku);
        }); 
        it('miku.nameはMikuになります', function() {
            var miku = new user.createUser('Miku');
            miku.should.have.property('name','Miku');
        }); 
        // 追加
        it('person.nameは与えられた名前を返します', function() {
            var person = new user.createUser('Ika Musume');
            person.should.have.property('name', 'Ika Musume');
            person = new user.createUser('NIKU');
            person.should.have.property('name', 'NIKU');
        }); 
    }); 
});


mocha実行。

        $ node_modules/mocha/bin/mocha 

  ...

  ✔  1 of 3 tests failed:

  0) User #createUser person.nameは与えられた名前を返します:
     AssertionError: expected { name: 'Miku' } to have a property 'name' of 'Ika Musume', but got 'Miku'
      at Object.property (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/should/lib/should.js:447:12)
      at Test.fn (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/test/user.test.js:16:32)
      at Test.run (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runnable.js:153:32)
      at Runner.runTest (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:271:10)
      at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:312:12
      at next (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:199:14)
      at /Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:208:7
      at next (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:157:23)
      at Array.0 (/Users/inouetomoyuki/Dropbox/Projects/node/mocha_example/node_modules/mocha/lib/runner.js:176:5)
      at EventEmitter._tickCallback (node.js:192:40)


user.jsを再び修正。

user.js

exports.createUser = createUser;
function createUser(name) {
    return {name:name};
}

mocha実行。グリーンになります。

$ node_modules/mocha/bin/mocha 

  ...

  ✔ 3 tests complete (30ms)


こんな感じで、テストコード作成→mocha実行(レッド)→user.js修正→mocha実行(グリーン)→リファクタを繰り返していきます。

0 件のコメント: