JavaScriptのテスト環境の構築


# JavaScriptのテスト環境を構築します

JavaScriptのテストがやりたかったのです。
環境は以下のとおりです。

* CentOS 6.5
* Node.js v0.11.10
* testem 0.6.2
* jasmine 1.3.1
* PhantomJS 1.9.2

# Node.jsのインストール

Node.jsを使いますのでインストールします。さっそくyum installだ！もしくはソースをダウンロードしてmake installだ！と、行きたい所ですが、Node.jsは

* 鬼のようにバージョンアップされる
* バージョンごとに挙動が違う(らしい)

という特徴を持っています。ということは、複数バージョンを入れて使い分けるという運用をしたくなりますね。
そんな願いを叶えてくれるNode.jsのバージョン管理ツールがいろいろあります。いろいろあってどれを使おうか迷うくらいです。
私は、

* プラットフォーム(bash,zsh)に依存しないように言語で書いてあってほしい
* /usr以下を汚さないように、home以下に入れてほしい
* インストールから実行までsudoなしで完結しててほしい
* バージョン切り替えが簡単にできてほしい

という願望を持って調べて見たところnodebrewが良さげでしたので、これを使うことに決めました。

## nodebrewでNode.jsをインストール

nodebrewの特徴はこんな感じです。

* perlで書かれている
* curlかwgetのワンライナーで入れる
* ~/.nodebrew以下にインストールされる
* インストールから実行までsudoが不要

じゃあさっそく入れてみましょう。
```curl https://raw.github.com/hokaccha/nodebrew/master/nodebrew | perl - setup```
これだけです。あとは`export PATH=$HOME/.nodebrew/current/bin:$PATH`このようにパスを通せばnodebrewコマンドが使えるようになります。

使い方はこんな感じです。

```
nodebrew ls-all #バージョン一覧を表示
nodebrew install latest # 最新版インストール
nodebrew install v0.10.x # 任意のバージョンを入れる時はこう書く
nodebrew install 0.10.x # v無しでも大丈夫
nodebrew use 0.11 #バージョン切り替え
```

私が最新版を入れたところ、v0.11.10 が入りました。

# testemとJasmineを使ったJSのテスト

Node.jsを入れたのでさっそく遊んでみたくなってきますが、今回の目的はJSのテスト環境を構築することです。当初の目的を見失わずにJSのテスト環境構築を目指しましょう。
そもそもなぜNode.jsを入れたのかと言いますと、Node.jsベースで動作するテストランナー`testem`を、`npm`を使って入れたかったからです。

## npm(Node Package Manager)

npm は Node Package Manager の略で Node.jsで作られたパッケージモジュールを管理するためのツールです。perlのcpanmのようなものですね。
nodebrewでNode.jsを入れたなら、`~/.nodebrew/current/bin/npm`に入っています。パスが通っていればnpmコマンドが使えます。
次のコマンドでtestemをインストールしましょう。

`npm install -g testem`

## testem

testemはJSのテストランナーです。JSのテストを簡単・快適にしてくれます。Jasmine/QUnit/Mochaの3つのテスティングフレームワークに対応しています。デフォルトではJasmineに設定されていますので、これでいこうと思います。

# さっそくテストをしてみましょう

testemを使ったテストをするために、次のようなディレクトリ構造を作ってください。

```
./
├ js/
│   └ fizzbuzz.js
├ spec/
│   └ test-fizzbuzz.js
└ testem.json
```

fizzbuzz問題をテスト駆動で解こうという意図ですね。
`testem.json`は設定ファイルです。次のように書けばいいと思います。

```json
{
    "framework" : [
        "jasmine"
    ],

    "src_files" : [
        "js/**/*.js",
        "spec/**/*.js"
    ]
}
```

設定ファイルや、testem自体の詳細を知りたい方は、 https://github.com/airportyh/testem こちらをご覧ください。

test-fizzbuzz.jsに次のように書いて下さい。

```js
describe("fizzbuzzメソッドのテスト", function() {

        describe ("#fizzbuzz", function() {

                it("3を与えたときFizzを返す", function() {
                        expect( fizzbuzz(3) ).toEqual('Fizz');
                });

        });
});
```

次にtestem.jsonがあるディレクトリでtestemを実行してください。

```
TEST'EM 'SCRIPTS!                                                                                                   
Open the URL below in a browser to connect.                                                                         
http://localhost:7357/  
```

こんな感じに出力されましたか?これは、testemを実行することでポート番号7357でウェブサーバが実行されてことを示しています。そのポートを指定してブラウザで http://localhost:7357/ にアクセスしますと、そのブラウザからのリクエストによってテストが実行され、テスト結果がブラウザ上に表示されます。コマンドラインにも表示されます。

テストは失敗しているはずです。fizzbuzzが未定義ですからね。では、テストが通るようにしてみましょう。
fizzbuzz.jsに次のように書けばテストが通るようになります。

```js
function fizzbuzz( input ) {

    return 'Fizz';
}
```

設定ファイルに指定したファイルを編集した時点でテストが実行されます。無事にテストが通れば、めでたしめでたしです。
ここまでできれば、あとはバリバリとコードを書いていってもいいいのですが、Webブラウザの存在は自動テストや継続的インテグレーションと相性が悪いという問題がありますし、何とかしたいという気持ちになるかもしれません。
そこでPhantomJSの出番です。

# PhantomJSを使ってヘッドレスなテスト環境を作る

http://phantomjs.org/
ここからPhantomJSをダウンロードして、`bin/phantomjs`をパスの通った場所において下さい。
そしたら`testem launchers`と実行してください。

```
$testem launchers
info Seeking for config file... 
Have 2 launchers available; auto-launch info displayed on the right.

Launcher      Type          CI  Dev
------------  ------------  --  ---
Firefox       browser       ✔           
PhantomJS     browser       ✔           
```

PhantomJSが表示されていることを確認したら、testem.jsonを次のように書き換えましょう。

```json
{
    "launch_in_dev" : [
        "PhantomJS"
    ],

    "framework" : [
        "jasmine"
    ],

    "src_files" : [
        "js/**/*.js",
        "spec/**/*.js"
    ]
}
```

testemを実行した時に、ブラウザを起動しなくてもテストが実行されていることが確認できたら大成功です。

それではFizz Buzz問題を解いてみてはどうでしょうか。きっと楽しいと思います。

![Screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/24415/1e2a8716-5dd7-dc6a-681a-a7b5c2289a8c.png)