node.jsでこんなのもテストしたい!! という話


テストフレームワークは、busterJSが一番慣れてたんですが、
部署御推薦の[mocha](http://mochajs.org/)をいっちょやってみるかー、と思っているこのごろです。

そしてついでに、
**「このへんは、node.jsの場合どうテストするのがかっこいいかしら!!」**
と気になっていた部分について、いろいろ調べてみました。

mochaの細かい説明については、[公式](http://mochajs.org/)その他をみてください。
mochaっていうかほとんど[should](http://npmjs.org/package/should)ですよね。

## 普通のテスト(libraryやcontrollerのテスト)

テストしたいmoduleをrequireして、
shouldもrequireして、テストを書く。これが基本ですね。

```javascript
// テストしたいmoduleをrequire
var hoge = require('../hoge');

// テスト用のライブラリをrequire (mochaの場合は、shouldがあればいいはず)
var should = require('should');

// あとはテストを書くのみ
describe('hoge', function () {
	it('足し算をする', function () {
		hoge.add(2, 3).should.equal(5);
	});

	it('割り算をする', function () {
		hoge.divide(6, 3).should.equal(2);
	});

	it('ゼロで割ったらぬるぽ', function () {
		// falseやnullを確認するときはこんな感じ
		should.not.exist(hoge.divide(5, 0));
	});
});

```



しかし、こうシンプルに書けない場合、
nodeのコードの中だけで完結しないようなコードは、どうテストするんだろう?
と気になってたわけです。

## express serverをテスト

たとえば、express serverのルーティング。
テストコード内で実際にサーバーを起動させて、
実際にURLを叩いてテストする…? とか思ってたんですが、
ここでいい感じのサンプルを見つけました。

- [コードで一言: CoffeeScriptとExpressとMongoDbとMochaでNode.jsするメモ](http://codedehitokoto.blogspot.jp/2012/02/coffeescriptexpressmongodbmochanodejs.html)

簡単に書くと以下。

```javascript
// expressのroutesのみrequire
var routes = require('../routes');

require('should');

describe('routes', function () {
	var req, res;

	beforeEach(function () {
		// 簡単に、フェイクのreqとresを用意
		req = {};
		res = {
			redirect: function () { },
			render : function () { }
		};
	});

	describe('index', function () {
		it('should display index page with title', function (done) {
			// res.render、すなわち表示用に呼ばれる関数をフェイクで作成
			// 事実上のcallback関数
			res.render = function (view, vars) {
				// 'index'というviewを使うことを確認
				view.should.equal('index');

				// 変数'title'が'Express'になっていることを確認
				vars.title.should.eql('Express');

				// テスト終了
				done();
			};

			// 実際に、routesのindexを実行 = アクセスしてみる
			routes.index(req, res);
		});
	});
});
```

ポイントは、

- expressの本体(app.js)ではなく、routesのみrequireすること
- res.renderをその場で書くことで、callback関数のような役割になる

ということ。

考えてみれば、expressは本体がかなり薄ーく作ってあるので、
routesだけテストすれば、ほぼサーバー自体のテストになるわけなんですね。
(urlとroutesの対応とかは、これでは見れてないけど)

あと、ここまで書いた後に改めて調べたら、
ちゃんと[express-test](https://npmjs.org/package/express-test)というnpmもあったので、
そちらを使った方が素直なのかもしれませぬ。


## cliをテスト

nodeで書くものといえばサーバー、あるいはコマンドラインツールですよね。
コマンドラインツールも、実際に実行してテストした方がいい…? とかいろいろ悩んでました。

これに関しては、[npmで"cli"keywordがついてるやつ](https://npmjs.org/browse/keyword/cli)をコードリーディングしてみました。

が、**どうやらあんまりテスト書かれてない…?**

[forever](https://npmjs.org/package/forever)とか[http-server](https://npmjs.org/package/http-server)とか[grunt-cli](https://npmjs.org/package/grunt-cli)とか、
"cli"の有名どころを読んでみたんですが、

本体のテストだけで、コマンドラインのインタフェース部分についてはテストされていない感じでした。
(gurnt-cliに関しては、全体通してもjshintしかしてない)
そ、そういうもんなのかな…?

とりあえず、

- cliの部分をできるだけ薄くして、オプション付け方とかまでどこかで書いてテストも書くとか、
- child_processで実際に実行してテストするとか、

ですかね。
また実際にやってみて考えます。


## mongooseなモデルをテスト

これはなんてこたぁない普通のテストだと思うんですが。

ただ、しばらくPerlばっかり書いてる時期があった名残で、
dbの初期化とかもかっこよく書きたい。
もっと言うと、node-configからtest用のconnect情報取って、つなぐとこまでは共通化して書きたい。

とか思ったので、test initスクリプトみたいなのを書いてみました。

```javascript:lib/test.js
 process.env.NODE_ENV = 'test';

var mongoose = require('mongoose'),
    config   = require('config'),
    async    = require('async');

require('should');

var test = function (initModels) {
    before(function (done) {
        async.series([function (next) {
            mongoose.connect(config.db.url, next);
        }, function (next) {
            async.forEach(initModels || [], function (model, next) {
                mongoose.model(model).remove(next);
            }, next);
        }], done);
    });
};

module.exports = test;
```

これで、テストコード本体で以下のように呼び出すだけで、

```javascript
require('lib/test')(['User']);
```

- envを'test'に設定
- configをenvで出し分けしてあるので、test用のconfig情報が読まれる
- beforeの中で、connectとdb初期化を実行
- ので、テストコード中ではそれらを意識しなくても勝手にやってくれる

といかんじでかっこいいです。

しかしbefore便利ですね。
テストコード中の非同期ネストが確実に減らせてうれしい。


## その他

- テストに使う固定のファイルは、```test/fixture```に置いているケースが多かった。

## まとめ

- mochaいい。
- Perlやっとくとテスト好きになってすごくいい。
- クライアントサイドのテストコードも読みたい。