Backbone.js を使った開発で QUnit を試してみた

最近は Backbone.js をよく触っています。Backbone.js を使った場合、そこそこな規模の UI が出来あがるわけで、品質を上げるためにはテストが必要不可欠です。

Backbone.js みたいな MVC フレームワークを導入するメリットとしては、「役割がはっきりしてソースコードがすっきりする」ことの他に、「テストがしやすくなる」というのもあると思います。クライアントサイド MVC に限ったことではないけど、ロジックをモデルに集約し、ビューは表示に徹することで、UI のかなりの部分が自動テストできます。

JavaScript のテストでは JsUnit と QUnit あたりが鉄板。JavaScript のテストライブラリは初めて使うので、軽くドキュメントを読んで簡単そうに感じた QUnit を選択します。試しに、モデルのテストを書いてみたのがこちら。

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>QUnit Test Suite</title>
        <link rel="stylesheet" href="qunit.css" type="text/css" media="screen">
        <script type="text/javascript" src="qunit.js"></script>
        <script type="text/javascript" src="underscore.js"></script>
        <script type="text/javascript" src="backbone.js"></script>
        <script type="text/javascript">
            // テスト対象のクラス。
            // Backbone のモデルを使ってみた。
            var Task = Backbone.Model.extend({
                defaults: {
                    name: "",
                    completed: false
                },
                complete: function() {
                    this.set({ "completed": true });
                },
                uncomplete: function() {
                    this.set({ "completed": false });
                },
                setName: function(name) {
                    if (_.isEmpty(name)) {
                        // 名前を空にしようとしたら例外を投げる
                        throw "name is required.";
                    }
                    this.set({ "name": name });
                }
            });

            var task;

            // module メソッドでテストをグループ化できる。
            // これ以降に定義されたテストは、次に module メソッドが呼び出されるまで、
            // このグループに属する。
            module("Task Test", {
                // テストの前処理
                setup: function() {
                    task = new Task({ "name": "foo" });
                },

                // テストの後処理
                teardown: function() {
                    delete task;
                }
            });

            // test メソッドでテストを定義する。
            test("コンストラクタのテスト", function() {
                // 期待している値かどうかは equal、notEqual でチェック。
                equal("foo", task.get("name"));
                notEqual(true, task.get("completed"));        
            });

            test("completeのテスト", function() {
                task.complete();
                equal(true, task.get("completed"));
            });

            test("uncompleteのテスト", function() {
                task.uncomplete();
                equal(false, task.get("completed"));
            });

            test("setNameのテスト", function() {
                // 例外が発生するかどうかのテストには raises メソッドを使う
                raises(function() {
                    task.setName("");
                }, "name is required.");
            });
        </script>
    </head>
    <body>
        <h1 id="qunit-header">QUnit Test Suite</h1>
        <h2 id="qunit-banner"></h2>
        <div id="qunit-testrunner-toolbar"></div>
        <h2 id="qunit-userAgent"></h2>
        <ol id="qunit-tests"></ol>
        <div id="qunit-fixture">test markup</div>
    </body>
</html>

上記の HTML を Web ブラウザで表示すると、テストが実行されます。
f:id:griefworker:20111028150101p:image

QUnit 初めて使ったんですけど、シンプルな API なので、すんなりと使い方を覚えることができました。jQuery に依存しなくなっているから、どんなアプリのテストにも使えます。HTML + JavaScript + CSS で構成されていて、ブラウザ上で実行できるので、導入もお手軽。正直、こいつの方が JsUnit っていう名前にふさわしいんじゃないか、って思えて仕方無いです。