javascriptのテストのはなし:QUnit(その3)

今回は非同期テストについてです。(前回[その2]前々回[その1]の記事も合わせどうぞ)
QUnitでは非同期のテストが可能になっています。基本的には非同期通信してそのコールバックでテストを実行するという感じですが、用意されているメソッドstart、stop(と、asyncTest)を使ってレスポンスが返ってくるのを待つ事が出来ます。

■各メソッドの役割

メソッド 説明
stop(increment) 非同期通信を行っている間、テストランナーを止める
start(decrement) 止まっているテストランナーを再び動かす
asyncTest(name, expected, test) 非同期通信のテストを行う
実態としてはtest()を実行した直後にstop()をしているので、test()で代用可能

stopとstartの引数については、APIの説明を読む限りstopとstartの対応付けで使う様ですが、期待通りには動かなかったので説明は保留します。
ただ、以前のバージョンだとstop()の引数はタイムアウトのミリ秒指定だった様ですが、現在のバージョンでは変わっている様です。タイムアウトのミリ秒指定についてはQUnit.config.testTimeoutで指定します。

■使ってみる

まずもっとも簡単なケースを試してみます。次の様にしてみました。

test("async", function(){
	stop();
	var res = $.get("./data/sampleData.txt", function(){
		start();
		equal(res.responseText, "sample", "first test");
	});
});

結果は次の様に問題なくテストできます。

では、上のコードでstop()をはずしてテストを実行します。
すると次の様にエラーになります。非同期を待たないでテストが終了してしまった為に、アサーションが一つもないと怒られました。

では、次にstop()を戻して、外部ファイルパスを存在しないパスにしてテストを実行してみます。すると、今度はstart()が呼ばれないのでテストランナーは止まったままになってしまいます。

これを解消するにはQUnit.config.testTimeoutを設定しておきます。例えば2000とすれば、2秒間レスポンスが無い場合テストを終了します。実行した結果次の様になり、テスト時間が2064millisecondsになっているので2秒でタイムアウトした事が分かりますね。

タイムアウトはテストメソッド毎に有効になるので、test()内で一度タイムアウトになると同一test()内の他のテストは実行されません。2回目の非同期通信のテストは行われていない事が分かると思います。

test("async", function(){
	stop();
	var res = $.get("./data/sampleData.tx", function(){
		start();
		equal(res.responseText, "sample", "first test");
	});
	var res2 = $.get("./data/sampleData.tx", function(){
		start();
		equal(res2.responseText, "sample", "second test");
	});
});
test("not async", function(){
	ok(true, "third test");
});

テストを分けると実行されます。実行結果が4155millisecondsになっているので、2回分タイムアウトしているのが分かります。

test("async", function(){
	stop();
	var res = $.get("./data/sampleData.tx", function(){
		start();
		equal(res.responseText, "sample", "first test");
	});
});
test("async2", function(){
	stop();
	var res = $.get("./data/sampleData.tx", function(){
		start();
		equal(res.responseText, "sample", "first test");
	});
});
test("not async", function(){
	ok(true, "third test");
});

ちょっとクセがありますが、非同期通信部分のテストを待てるというのはありがたいですね。

■気を付けておくこと

最後に気を付けておくことを一つ。
stop()を使う事でテストがキューイングされる事が分かったわけですが、下記のようなテストを実行するとどうなるでしょう。

var flag = true;
test("async", function(){
	stop();
	var res = $.get("./data/sampleData.txt", function(){
		start();
		equal(res.responseText, "sample", "first test");
		ok(flag, "value of flag");
	});
});
test("async2", function(){
	stop();
	var res = $.get("./data/sampleData.txt", function(){
		start();
		equal(res.responseText, "sample", "second test");
	});
});
test("not async", function(){
	ok(true, "third test");
});
flag = false;

結果は次の通りで、flagのテストが通りません。キューイングされるのがtest()だけで、それ以外のコードは先に実行されてしまいます。