2009年3月19日

Tips

YUI Testを使ったJavaScriptユニットテストのすすめ

  • このエントリーをはてなブックマークに追加

こんにちは、検索事業部の角田です。

私が担当しているプロジェクトではPHPUnitSeleniumを使ってテストを行っています。そして、最近YUI TestというJavaScriptによるユニットテストライブラリを使い始め、JavaScriptのユニットテストがとてもいい感じに思えてきたのでご紹介します。

YUI Testは、Yahoo! Developer Networkにて公開されているYahoo! UI Libraryの数多くあるコンポーネントの中の一つです。その名の通り、JavaScriptのユニットテストを行うライブラリです。JavaによるJUnitやPHPによるPHPUnitを使ったことのある方であれば、すぐに使い方を覚えられます。しかし、あまりYUI Test(に限らずJavaScriptのユニットテストライブラリ)を使ったブログ記事やプロダクトを見かけたことがないので、ここで簡単に紹介しておきます。

サンプルの題材として「全角英数字を半角に変換するJavaScriptをテストしたい」とします。以下にサンプルのHTMLを用意しましたので、任意のエディタにコピー&ペーストして保存し、ブラウザで表示してみてください。サンプルコードにてJavaScriptコンソールにログを出力する console.log() 等を使っているため、console APIをサポートしているブラウザ(Firefox, Safari, Google Chrome)をオススメします。IEの場合はYUILogger Controlを使うとWidgetを使ったログ出力の確認が可能です。この記事ではFirebugをインストールしたFirefoxを使用します。

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>YUI Test Sample</title>
<script type="text/javascript">
function $(n) { return document.getElementById(n); }
function to_hankaku(str) {
    return str.replace(/([A-Za-z0-9])/g,
                       function (s) {
                           return String.fromCharCode(s.charCodeAt(0) - 65248);
                       });
}
</script>
</head>
<body>
<p>YUI Test Sample</p>
<input type="text" id="from" value="Yahoo" />
<input type="submit" onclick="$('to').value = to_hankaku($('from').value);" />
<input type="text" id="to" value="" />
</body>
</html>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/logger/logger-min.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.7.0/build/yuitest/yuitest-min.js"></script>
<script type="text/javascript">
(function() {

var oTestCase = new YAHOO.tool.TestCase({
    name: "to_hankaku Test",
    testToHankaku: function() {
        var Assert = YAHOO.util.Assert;
        Assert.areEqual('Yahoo', to_hankaku('Yahoo'));
        Assert.areEqual('123', to_hankaku('123'));
        Assert.areEqual('Yahoo!', to_hankaku('Yahoo!'));
        // Assert.areEqual('TB-303', to_hankaku('TB−303')); // failed test case
    }
});

var TestRunner = YAHOO.tool.TestRunner;
TestRunner.subscribe(TestRunner.TEST_PASS_EVENT, function(data) {
    console.log(data.testName + " passed.");
});
TestRunner.subscribe(TestRunner.TEST_FAIL_EVENT, function(data) {
    console.error(data.testName + " failed with message: " + data.error.getMessage());
});
TestRunner.add(oTestCase);
TestRunner.run();

})();
</script>

このHTMLをブラウザで読み込むと、2つのテキストフィールドと1つの送信ボタンが表示されます。
tech blog 20090318_1
実行ボタンを押すと送信ボタンのonclick属性に記述しているJavaScriptが実行され、headタグ内に定義しているto_hankaku()関数を呼び出します。これにより、左側のフィールドに入った「Yahoo」という全角文字が「Yahoo」という半角文字に変換されて右側のフィールドに入ります。ちなみにサンプルの便宜上としてここではonclick属性を使っていますが、実際のコードではイベントハンドラを使った方がよりよいでしょう。この点については良質のブログ記事があるので別途参照することをオススメします。

さて、ここで注目すべきはhtmlタグ以降に記述されたJavaScriptコード群です。まずYUI Testに必要なライブラリを読み込んでいます。YUI Testに依存するライブラリは yahoo-dom-event.jslogger-min.js です。そしてYUI Test本体に相当するのが yuitest-min.js です。そして本題であるYUI Testを使ったユニットテストのコードが書かれています。

YUI Testのテストケースは、YAHOO.tool.TestCase のコンストラクタとしてテスト内容を定義します。サンプルコードにある testToHankakuの ように、テストメソッドは test で始まる名前で定義します。そして YAHOO.util.Assert の各種アサーションメソッドを使って期待値(expected)と実際の値(actual)を比較します。

テストを実行するには YAHOO.tool.TestRunner を使います。 YAHOO.tool.TestRunner.subscribe() メソッドにてテストが成功、失敗した時の動作を定義します。サンプルコードでは console.log() を使ってブラウザのJavaScriptコンソールにログ出力をしています。

そして YAHOO.tool.TestRunner.add() メソッドにてテストケースを登録し、 YAHOO.tool.TestRunner.run() メソッドにてテストケースを実際に実行します。ブラウザのJavaScriptコンソールを見ると、

testToHankaku passed.

のようなログが出力されています。
tech blog 20090318_2
では、テストが失敗した時はどうなるでしょう。サンプルコードのコメントアウトされているテストコードのコメントを外してブラウザを更新してみましょう。

Assert.areEqual('TB-303', to_hankaku('TB−303')); // failed test case

すると、以下のようなエラーログが出力されます。

testToHankaku failed with message: Values should be equal.
Expected: TB-303 (string)
Actual:TB−303 (string)

tech blog 20090318_3
FirefoxにFirebugをインストールしていると、ステータスバーにエラーが表示されるので便利です。ここでは全角の「−」記号が半角に変換されないため期待値と異なり失敗しました。to_hankaku()関数が英数字だけでなく記号もサポートするのであればto_hankaku()関数を修正しなければいけません。記号の変換はサポートしなくてもよいのであれば、期待値の方を修正する必要があります。これは実際に使うプロダクトの仕様によるでしょう。

これまで、YUI Testを使ったJavaScriptによるユニットテストを紹介してきました。使いはじめはとても面倒に思えますが、一度慣れてしまうと楽にテストが書けます。また、最大のメリットとして 「ブラウザに表示させるだけでテストを実行できる」 という点が挙げられます。冒頭で「JavaScriptのユニットテストがとてもいい感じ」と述べたのはこの点です。

PHPUnitSeleniumなどはコマンドをたたくなどして明示的に実行しないとテストを実行しません。HudsonCruiseControlなどのContinuous Integrationツールを使って定期的に実行したり、stakeoutのような仕組みを使ってファイルが保存された時にテストを実行するなどいろいろな工夫も考えられます。しかしJavaScriptのユニットテストの場合、単にブラウザを更新するだけでよいのです。(HTMLやJavaScriptを保存した時にブラウザを更新する仕組みを作る方法もあるようですが、私はそこまでやっていません)

このように、YUI Testを使うと他のユニットテストと同じ方法で手軽にJavaScriptのテストができます。JavaScriptコードを更新するたびに何度もキーボードをタイプしたり、マウスを持ってボタンをクリックしたりする必要はありません。ページが表示され、コンソールにエラーログが出なければすべてのテストに成功したことになるのです。

しかし、実際のプロダクション環境にテストコードをそのまま埋め込むのはあまり気分がよくありません。私の場合は、htdocs以下にあるjsディレクトリの下にtestというディレクトリを作成し、その配下にYUI Testを含む一連のテスト用JavaScriptコードを置いています。そして、開発環境用、本番環境用のようにプロジェクト構成を分け、開発環境にデプロイする時のみテストコードを配置し読み込むようにしています。

YUI Testにはここで紹介した基本的な機能のほかにレポート出力やブラウザ操作をシミュレートする機能なども含まれており非常に高機能です。まずは基本的な使い方を覚えて、JavaScriptのユニットテストにチャレンジしてみてはいかがでしょうか。

Yahoo! JAPANでは情報技術を駆使して人々や社会の課題を一緒に解決していける方を募集しています。詳しくは採用情報をご覧ください。

  • このエントリーをはてなブックマークに追加