rhinounitでJavaScriptのユニットテスト

JavaScriptユニットテスト フレームワークって何があるかなって探してみた。JsUnitが定番っぽいけど、実行してもこんな感じのエラーが出て何かうまくいかない。

エラー: Component returned failure code: 0x80520012 (NS_ERROR_FILE_NOT_FOUND) [nsIDOMLocation.href]

他を探したら、rhinounitってのを見つけた。だいぶマイナーだけど、試してみたらちゃんと動いたのでそのメモ。

事前準備

まず、rhinounitを動かすのに必要な環境をそろえる。最低限必要なのはこれ。

テストはantで実行する(めんどくさいぜ)。

あと、RhinoってのはJavaで書かれたJavaScriptの実装。こいつがあるとブラウザなしでコマンドラインからJavaScriptが実行できる。

僕はUbuntu使いなので全部apt-getで簡単インストール。今回インストールしたパッケージは以下。

  • sun-java6-jre
  • ant
  • rhino

ついでに以下もインストールしておいた。

  • sun-java6-jdk
  • ant-doc
  • rhino-doc

Rhinoをソースコードからインストールしたい人は公式のダウンロードページからゲットしよう。

Rhinoの練習

コマンドラインからRhinoが実行できるようになったはずなので、ちょっと練習してみる。

% rhino # 対話モードで起動
Rhino 1.7 release 1 2008 11 26
js> print("test")
test
js> quit()

終了するには quit() 。最後に () をつけないと終了できない。

あとはMDCのドキュメントを見ながら適当に動かしてみた。

2009/8/9 追記

Ubuntu環境では、rhinoの実体はこんな感じのシェルスクリプトになってる。環境によってはこのコマンドを直接実行しても良いだろう。

#!/bin/sh

/usr/bin/java -jar /usr/share/java/js.jar $@

rhinounitのインストール

で、rhinounit本体のインストール。といっても、rhinounit公式サイトダウンロードページからzipアーカイブをダウンロードするだけ。特にインストール作業はいらない。

展開するとJavaScriptファイルとbuild.xmlファイルがあるので、antコマンドを実行してみる。うん、ちゃんと「BUILD SUCCESSFUL」って出てきた。いい感じ。

テストを書く

ここまでで準備は完了。いよいよテストを書いてみる。今回作ったファイルは以下。

% tree -F
.
|-- build.xml
|-- src/
|   `-- code.js
`-- test/
    |-- firstTest.js
    `-- rhinounit/
        |-- rhinoUnitAnt.js
        `-- rhinoUnitUtil.js

ファイルの説明。

build.xml
テストを実行するためのantファイル。rhinounit の build.xml を元に作成。
code.js
テスト対象となるコード。
firstTest.js
テストコード。
rhinoUnitAnt.js
テストフレームワークのコード。rhinounit の src ディレクトリからコピー。
rhinoUnitUtil.js
テストフレームワークのコード。rhinounit の src ディレクトリからコピー。

自分で書くのは最初の3つだけだ。

書いたコードはこんな感じ。

build.xml
<project name="" basedir="." default="run-all-tests">
  <target name="run-all-tests" depends="run-unit-tests"/>

  <scriptdef name="rhinounit"
      src="test/rhinounit/rhinoUnitAnt.js"
      language="javascript">
    <attribute name="options"/>
    <attribute name="ignoredglobalvars"/>
    <attribute name="haltOnFirstFailure"/>
    <attribute name="rhinoUnitUtilPath"/>
    <element name="fileset" type="fileset"/>
  </scriptdef>

  <target name="run-unit-tests">
    <rhinounit options="{verbose:true, stackTrace:true}"
        ignoredglobalvars="rhinounit" rhinoUnitUtilPath="test/rhinounit/rhinoUnitUtil.js">
      <fileset dir="test">
        <include name="*.js"/>
      </fileset>
    </rhinounit>
  </target>
</project>
code.js
// この関数をテストする
function triple(x) {
    return x * 3;
}
firstTest.js
eval(loadFile("src/code.js"));

testCases(test,
    function firstTest() {
        // assert.that(actual, eq(expected)) の形式で書く
        assert.that(triple(4), eq(12));
    },
    function firstTest2() {
        assert.that(triple(5), eq(15));
    }
);

最後の loadFile のところは、テスト対象のJavaScriptファイルをbuild.xmlがある場所からの相対パスで書けばOK。

あとは build.xml ファイルで rhinoUnitAnt.js, rhinoUnitUtil.js のパスを指定するので、自分の環境に合わせて編集しよう。

テストを実行する

ではテスト実行。

% ant
Buildfile: build.xml

run-unit-tests:
[rhinounit] Testsuite: firstTest.js
[rhinounit] Tests run: 2, Failures: 0, Errors: 0
[rhinounit]

run-all-tests:

BUILD SUCCESSFUL
Total time: 0 seconds

やった、テスト合格。

これ以外にもjslintを使った構文チェックもできるみたい。

最後に

というわけでrhinounitを試してみた。JsUnitとの最大の違いは、JsUnitはブラウザから実行するけどrhinounitはコマンドラインから実行する、ってとこ。antで依存関係を解決できるので、build.xmlファイルをちゃんと書けばブラウザで実行するよりも速いと思う。その代わりブラウザ依存のテストはできない。必要に応じて使い分けるといいと思うよ。