JavaScript Test with QUnit and mockjax
JavascriptのテストはXHRがネック
JavaScriptを書いていると、RESTサービスを利用してXHR(XMLHttpRequest)やjQuery.ajax経由で
JSONのやり取りをする処理を実装することが多い。
こういった処理は以下の理由からテストが書きにくい。
1.サーバサイドの実装状況に依存する
2.非同期処理
JavaScriptを始めたばかりの時はjsUnitを使ってテストを書いていたのだが、
この2点はいつもネックになっていた。
QUnitとmockjaxでだいたい解決する
新しいテストフレームワークをいろいろと試してみた結果、jQueryのテストフレームワークQUnitと
jQueryライブラリのmockjaxを使えば自分が書く実装の大部分が解決できることがわかった。
QUnitについては色々と日本語の情報があるのだが、mockjaxについては
ほとんど見られなかったのでメモ書きとして残す。
QUnitの使い方はこのへんを見た
jQuery.mockjaxってなに?
mockjaxはjQueryのjQuery.ajaxにたいしてモックを提供してくれるjQueryプラグイン。
これを用いることでRESTサービスを利用するフロントエンドの開発を行う際に
サーバー側の実装が完了する前から通信部分の実装・テストを行うことができる。
mockjaxの使い方
簡単な使い方は以下のようになる。
こんな感じのJSONデータを受け取りたいとする。
{"status":"success", "fortune":"Are you a turtle?" }
うけとる処理はこんな感じ
function getFortune(){ $.getJSON('/restful/fortune', function(response) { if ( response.status == 'success') { retun 'Your fortune is: '.concat(response.fortune); } else { return 'Things do not look good, no fortune was told'; } }); }
通常、サーバー側のサービスが存在しないとこのコードはテストできない。
そこで、mockjaxを使ってテストコードの中でモックを作成する。
test("asynctest", function(){ //モックを作成 var id = $.mockjax({ url: '/restful/fortune', responseTime: 750, responseText: { status: 'success', fortune: 'Are you a turtle?' } }); //処理の実行 var fortune = getFortune(); stop(); setTimeout(function(){ start(); //評価 notEqual(fortune,'Things do not look good, no fortune was told', 'サーバーから結果を取得する'); //mockのお片づけ $.mockjaxClear(id); }, 500); });
これだけで、GETだろうがPOSTだろうがmockjaxが$.ajaxを拾って
あらかじめ設定しておいたレスポンスを返却してくれる。
「想定してなかった」ことに対するテストはやっぱり本物のサーバーサービスに接続する必要があるけど、
とりあえずの実装ならこのモックで十分事足りる。HTTP Statusも指定できるので、異常系のテストも書くことが出来る。
応用編1 urlの指定をする
mockjaxのurl指定はかなり柔軟に設定できる
- 普通に指定
$.mockjax({ url:'/url/to/service' });
- 特定のパス以下を全部拾う
$.mockjax({ // /url/to/service も url/to/pathも該当する url:'/url/to/*' });
- 正規表現でマッチするurlを指定
$.mockjax({ // url/to/path と url/to/service にはマッチするけど url/to/services にはマッチしない url: /^\/url\/to\/(path|service)$/i });
応用編2 レスポンスの形式を変更する
最初の例でjsonで返却する例を示したが、テキスト・XMLでも返却できる
- テキストで返す
$.mockjax({ url:'/url/to/service', responseText:'response letter from server mockup' });
- XMLで返す
$.mockjax({ url: '/url/to/service', responseXML: '<document><quote>This is response letter!</quote></document>' });
応用編3 proxyをかませる
特定のURLでリクエストをうけてリダイレクトできる
$.mockjax({ //このURLで受けて url:'/url/to/service', //このURLにリダイレクトする proxy:'path/to/test.json' });
応用編4 コールバック処理を指定する
$.mockjax({ url:'/url/to/service', response: function() { //responseTextまたはresponseXMLを必ず設定する必要がある this.responseText = 'This is resposen letter!' } });
応用編5 レスポンスパラメーターを指定する
$.mockjax({ url: '/url/to/service', // レスポンスを一定時間遅らせる responseTime : 750, // HTTP Status Codeを指定する status : 200, // Content-Typeを指定する contentType : 'text/json', // HTTP response Headerを指定する header : { Access-Control-Allow-Origin : '*' }, // リクエストにサーバータイムアウトを返却する isTimeout : true, });
その他 モックオブジェクトの後片付け
- すべてのモックオブジェクトを削除する
$.mockjaxClear();
- 特定のモックオブジェクトを削除する
var mockId = $.mockjax({ url : .... }); $.mockjaxClear(mockId);
こんな感じ。長かった...。