javascript、いや、jQueryのテストツールQUnit使ってみた
しかだよ。
久々にajaxなお仕事に携わってjavascript(むしろjQuery)書きました。んでテストコード書きたいので調べたらJSUnitとQUnitを見つけました。QUnitはjQueryから派生したツールらしいので迷わずQUnitにしました。jQueryのテストが簡単に書けるのでいいですね。
functionのテスト
テストはこんな感じ。たぶん動くよ。
//テスト対象のサンプルコード /* * px文字列を数値にする。 * sample "100px" -> 100 */ var changePxInt = function(px_str){ if('number' == typeof(px_str)){ return px_str; } var index = px_str.search("px"); if(index < 0){ return 0; } return Number(px_str.slice(0,index)); };
//テストコード $(function(){ module("function test"); test("changePxInt function", function(){ var test1 = changePxInt("20px"); equal(20, test1, "normal test"); var test2 = getPxInt("0px"); equal(0, test2, "normal test not number"); var test3 = getPxInt("px"); equal(0, test3, "abnormal test bad string px"); var test4 = getPxInt("20p"); equal(0, test4, "abnormal test bad string 20p"); var test5 = getPxInt(""); equal(0, test5, "abnormal test empty"); }); });
イベントのテスト
clickとかhoverとかのイベントのテストはこんな感じ。bindとtriggerでイベントを意図的に呼んでテストする感じ。
//テスト対象のサンプルコード $(function(){ /* * 画像へのマウスオーバーで画像を変換する。 */ $.fn.imgOver = function(param){ $(this).hover(function(){ var src = $(this).attr("src"); var prefix = src.slice(src.lastIndexOf('.')); var name = src.slice(0,src.lastIndexOf('.')); var onname = name + param + prefix; $(this).attr("src",onname); },function(){ var src = $(this).attr("src"); var outname = src.replace(param,""); $(this).attr("src",outname); }); return this; }; });
//テストコード $(function(){ test("hover", function(){ var $img = $("<img>").attr("src", "test.jpg").imgOver("_o"); //testを評価するfunction var over_handler = function(event, data){ equal("test_o.jpg" , img.attr("src"), "normal test mouse over"); }; var out_handler = function(event, data){ equal("test.jpg" , img.attr("src"), "normal test mouse out"); }; //bindで評価するfunctionを渡して、 //triggerでイベントを呼ぶ $img.bind("mouseover", over_handler) .trigger("mouseover") .unbind("mouseover", over_handler); $img.bind("mouseout", out_handler) .trigger("mouseout") .unbind("mouseout", out_handler); }); });
非同期処理のテスト
例えばjsonを取得してそのデータを元にごにょごにょする場合は、テストの実行と、データを取得するまでのズレが発生するのでsetTimeoutでいい感じに調整する。
//testじゃなくてasyncTestを使う。 asyncTest("find", function(){ //テストしたい非同期な処理 $.getJSON("index.json", function(data){ this.model = new modelObj(data); }); //第3引数に数値を渡し、実行するタイミングを遅らせる。とりあえず100mにしてみた。 setTimeout(function(){ //100ms経ったら動き出す! start(); var test1 = this.model.find("test"); equal("test", test1.name, "normal test"); var test2 = this.model.find("shikajiro"); equal(undefined, test2, "abnormal test"); },100); });
前処理、後処理
テスト毎に前処理後処理はmoduleの第2引数にfunctionを定義できる。setupに前準備の処理、teardownにテスト後の処理(オブジェクトの後始末とか)を書く。
module("async test",{ setup: function() { $.getJSON("index.json", function(data){ this.model = new modelObj(data); }); }, teardown: function(){ this.model = undefined; } });
感想
今回はテストファーストじゃなくて実装した後にテストコード書いたんだけど、テストコードを書けば書くほど設計の悪さが浮き彫りになりました。やっぱテストは大事ですね。リファクタリングも出来るようにもなったし大満足。javascriptの仕様をあんまり理解してないので、うまく書けない。(´・ω・`)
とりあえず上記くらいのパターンが書ければだいたいのテストはできると思う。アニメーションのテストは難しそう。今回は書かないことにした。今度本気出す。( ー`дー´)キリッ
まとめサイト
わかりやすい使い方、詳細は以下サイトを見たほうがいいです。
QUnit - jQuery JavaScript Library
jQueryのテスティングフレームワークQUnit (でぃべろっぱーず・さいど)
QUnitの基本的な使い方 - but hopeful