QUnitとは
JavaScript用のTestingFrameworkです。
由来
jQueryのテスト用に作られ、今もjQuery、jQuery-UIのテストに使われています。
それ自体はjQueryに依存していませんが、テスト内でDOMを操作したりイベントを生成したりするのにjQueryを使うと便利です。
JavaScript的な側面
実行環境
QUnitとテスト用のスクリプトをブラウザに読み込んで実行します。
テスト結果はそのままブラウザに表示します。
他のツールと連携すると
- PhantomJSを使えばCLIで実行可能
- Testemを使うとテスト修正時の自動リロード(再実行)が可能
- Gruntからもgrunt-contrib-qunitプラグインを使って実行可能
ちなみに、mochaというTestingFrameworkはnode.jsで実行します。
インストール
npmで入れることもできますが、scriptタグでブラウザに読み込むのでソースをローカルに置くか、CDNから取得するのが一般的です。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Example</title>
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.12.0.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="http://code.jquery.com/qunit/qunit-1.12.0.js"></script>
<script src="tests.js"></script>
</body>
</html>
test.jsはこのような内容です。
test("hello test", function() {
ok(1 == "1", "passed!");
});
TestingFramewokとしての側面
xUnitの一種である。テストケースとアサートでテストを記述する。
ちなみに、JasmineというTestingFrameworkはBDD形式で記述します。
テストケース
テストケースはtestという関数で記述します。
test("hello test", function() {
ok(1 == "1", "passed!");
});
第一引数がテストケース名で第二引数に内容を書きます。
アサート
アサート用の関数は3種類あります。
- ok
- equal
- throws
OK
真であるか判定します。
test("ok test", function() {
ok(true, "true succeeds");
ok("non-empty", "non-empty string succeeds");
ok(false, "false fails");
ok(0, "0 fails");
ok(NaN, "NaN fails");
ok("", "empty string fails");
ok(null, "null fails");
ok(undefined, "undefined fails");
});
equal
二つの値が同じであるか判定します。
test("equal test", function() {
equal(0, 0, "Zero, Zero; equal succeeds");
equal("", 0, "Empty, Zero; equal succeeds");
equal("", "", "Empty, Empty; equal succeeds");
equal("three", 3, "Three, 3; equal fails");
equal(null, false, "null, false; equal fails");
});
equalは==で比較するため型変換されます。===で比較するstrictEqual関数もあります。
test("strict equal test", function() {
strictEqual(0, 0, "Zero, Zero; strict equal succeeds");
strictEqual("", 0, "Empty, Zero; strict equal failss");
strictEqual("0", 0, "String Zero, Number Zero; strict equal failss");
});
オブジェクトや配列の中身を比較するdeepEqualもあります。
test("deepEqual test", function() {
var obj = {
foo: "bar"
};
deepEqual(obj, {
foo: "bar"
}, "Two objects can be the same in value");
});
それぞれ異なることを判定するための関数があります。
- notEqual
- notStrictEqual
- notDeepEqual
throws
例外が出ることを確認します。
test("throws", function() {
throws(
function() {
throw "error"
},
"throws with just a message, no expected"
);
});
Callbackのテスト
Callback関数が呼ばれるかどうかをテストする方法があります。
同期コールバック
イベントハンドラーなどの即座に呼び出されるコールバックの確認にはexpect関数を使います。
test("a test", function() {
expect(1);
var $body = $("body");
$body.on("click", function() {
ok(true, "body was clicked!");
});
$body.trigger("click");
});
expectの引数は想定する、okなどアサート関数の呼び出し回数です。
test関数の第二引数に指定することもできます。
test("a test", 1, function() {
var $body = $("body");
$body.on("click", function() {
ok(true, "body was clicked!");
});
$body.trigger("click");
});
非同期コールバック
Ajaxなどの即座に帰ってこないコールバックはコールバックの呼び出しを待つことができます。
このときはtest関数の代わりにasyncTest関数を使います。
asyncTest("asynchronous test: video ready to play", 1, function() {
var $video = $("video");
$video.on("canplaythrough", function() {
ok(true, "video has loaded and is ready to play");
start();
});
});
テストの実行を止め、start関数が呼ばれるまで待ちます。
テストケースのグループ化
module関数を使うとテストケースをグループ化できます。
module("group a");
test("a basic test example", function() {
ok(true, "this test is fine");
});
test("a basic test example 2", function() {
ok(true, "this test is fine");
});
module("group b");
test("a basic test example 3", function() {
ok(true, "this test is fine");
});
test("a basic test example 4", function() {
ok(true, "this test is fine");
});
モジュールにはsetup/teadown関数を指定してできます。これらの関数は各テストの実行前後に呼び出されます。
module("module", {
setup: function() {
ok(true, "one extra assert per test");
},
teardown: function() {
ok(true, "and one extra assert after each test");
}
});
test("test with setup and teardown", function() {
expect(2);
});
その他
テスト対象のDOM
テスト対象のDOMはqunit-fixture要素に追加します。
qunit-fixture要素はテスト終了毎にクリアされます。
テスト同士が影響を及ぼしあうのを防ぎます。
test("Appends a div", function() {
var $fixture = $("#qunit-fixture");
$fixture.append("<div>hello!</div>");
equal($("div", $fixture).length, 1, "div added successfully!");
});
test("Appends a span", function() {
var $fixture = $("#qunit-fixture");
$fixture.append("<span>hello!</span>");
equal($("span", $fixture).length, 1, "span added successfully!");
});
ユーザ操作のエミュレーション
jQueryのtrigger関数を使ってください。
グローバル汚染チェック
テスト実行時のURLのクエリパラメータに noglobals=true を指定するとテスト内でグローバル変数が追加・削除されていない確認することができます。
結果画面のチェックボックス「Check for Globals」にチェックを入れても一緒です。