EagleLand

2013.08.19

Travis CIを使ったGitHubプロジェクトの継続的インテグレーション

今更感が否めないけど、簡単にまとめた。Travis CIとはなんぞやという方はこちら。継続的インテグレーションとはなんぞやという方はこちら。

例えばテストの自動化をして、リファクタリングのしやすい環境を作って、コードの品質向上を継続的に行っていくサイクル。というイメージ。今回はGitHubとTravis CIで自動化を測るけど、Jenkinsでビルド環境を整えて、継続的にデプロイをしていくのもひとつのCIである。

テスト周りの環境とか

オレオレライブラリにCI環境整えた。mochaでBDDのテストケースを書いて、イベントのバインド周りのテストはsinon#spy()を。testem + PhantomJSでそのテストをで実行させるといった流れ。

mochaのサンプルは公式ドキュメントがわかりやすい。イベント周りにSinonを。mocha単体だと少しテストしにくいからだけど、その理由については@hokacchaさんのスライドが非常にわかりやすいのでこちらを見て欲しい。

サンプルリポジトリと詳しい手順

上記を踏まえて最低限のScaffoldを作成した。Travis CIではC++やらJavaやらRubyやらGoやらと、色々な言語に対応しているが、今回はnode.jsを使ったJavaScriptのテストについて。もともとはRubyのためのサービスとして始まったそう。

.travis.yml

Travis側に自動で認識される設定ファイル。このファイルにTravis CI側から実行される処理を定義します。今回はnode.js経由で行うJavaScriptのテストを定義する。その他のケースでどうするかは公式ドキュメントを見て欲しい。

こちらは.travis.ymlのサンプル。

language: node_js
node_js:
    - "0.10"
before_script:
    - npm install bower
    - ./node_modules/bower/bin/bower install
script:
    - "npm test"

特に指定なくても、npm testがデフォルトで実行される。Gruntとかにテストタスクを書いてある場合はそれをscript:の箇所に記述すれば良い。

bower.json

before_scriptはお分かりの通りscriptの前に実行されるコマンドだが、ここではテストライブラリのインストールをbower経由で行うべく、事前にbower自体のインストールと、bower.jsonに定義したテストライブラリをダウンロードしている。npm経由だとnodeとしてパックされたものが落ちてきてしまうので。

また、sinonについてはbowerでもnode用でダウンロードされてしまうようなので、直接指定している。(サンプルリポジトリのbower.json参照)

package.json

順番が前後するが、.travis.ymlで実行されるscriptの前にnpm installが実行される。ここではdevDependenciesにtestemを指定し、scriptsのtestにローカルインストールされるtestemを指定した。

testem周り

npm installされて、package.jsonに定義されているnpm testされて、./node_modules/testem/testem.js -l PhantomJS ciが実行されるところまで出来た。testemの設定はtestem.jsonに指定する。

なお、testemはrunnerページを作成したりテストライブラリをダウンロードせず(今回bowerで落としてるmochaとかchaiとか)testem.jsonだけの指定でアレコレできるのだけど、sinon等のテストヘルパーが結局必要になったりするなど、カスタムで設定してしまうほうが後々楽だと思う。

{
  "test_page": "./spec/runner.mustache",
  "serve_files": [
    "./src/target.js",
    "./spec/*.js"
  ],
  "launch_in_dev": ["PhantomJS"]
}

test_pageはrunnerページの指定、serve_filesはrunnerページで扱うファイルを動的に定義。runner.mustacheを見てもらうとわかるが、中はHTML構造で、bowerでインストールされているはずのライブラリのロードやmochaの実行を行っている。

ローカルで実行してみる

Travisで実行されるであろう順にローカルで実行してみる。bowerとかtestemとか、ローカルのグローバルにインストールされているかもしれないが、ここでは敢えて使っていない。

# bower自体のインストール
$ npm install bower

# bowerでテストライブラリのダウンロード
$ ./node_modules/bower/bin/bower install

# package.jsonの依存関係を解決
# ここではtestemがインストールされる想定
$ npm install .

# testemを実行する
$ ./node_modules/testem/testem.js

実行されただろうか。localhostにもサーバーが立ち上がって、mochaの実行結果ページにアクセスできるようになるはず。一度実行されると、ファイルの変更を検知してテストの再実行も自動的に行われるようになる。

Travis CIの設定をonにする

ここにアクセスして、travisのCI対象にしたいGitHubリポジトリを on にする。あとは、GitHubに対してpushするだけで、その度に.travis.ymlの設定に沿って処理が実行される。また、Pull Requestされた場合にも自動的にテストが行われる。素晴らしい。

所感

今回はnpm test経由でtestemを実行させているけど、前述のとおりGruntにテストタスクを書いてそちらを実行させても構わない。

ローカルでもテストは実行するけど、TravisみたいなCIと連携させて、漏れ無く自動的にテストできるのは良い。Testable JavaScriptの中で触れられていますが、リファクタリングを前提に考えることで躊躇なくソースコードを直すことが出来る。もちろん、テストが網羅されている前提の話ではあるけど。