fc2ブログ

QUnit+jQueryで、チンチロリンゲーム自動実行テストプログラムを作った

先日機能追加したチンチロリンのゲームを、ちょこちょことテストしている。
function単位の単体テスト以外に、自動実行させて動作確認するテストも行った。

せっかくなので、QUnit+jQueryで作った自動実行テストプログラムをアップした。
ccrmain.js full action Test
ccrmain.js full action Test
(ページを開くといきなり動き出します。HTML5 Canvasをサポートしていないブラウザでは正しく表示されません。
テストシナリオが崩れるので、ゲームのボタンは押さないでください)
右側にテスト結果が表示される。正常なら青になる。

テストを実行するJavaScriptソースは以下。
ccrActionTest.js (文字コードはUTF-8)

テストプログラムの流れを簡単に解説する。
1. $(window).load の実行を待つ
asyncTest("wait for onload", function() {...}); の部分
asyncTest()で、$(window).load が実行されるまで待つ。
asyncTest()でのイベント処理テストについては、QUnit & jQuery でイベント起動処理のテストを行う を参照。

2. ランダム処理部分を上書き
test("replace method", function() {...}); の部分
最初の親とサイコロの目はランダムに決めている。
シナリオに従って動作するよう、該当メソッドを上書きしている。

3. サイコロを振って、振り終わるのを待ってスコアチェック
jQueryのclick()などでイベント発行してサイコロを振る。
asyncTest()で、サイコロを振り終わるまで待つ。
次の親がプレイヤー(3Dサイコロ)のときは処理が勝手に進んでしまうので、asyncTest()内でメインループを止める処理を実行して処理を止めている。

今回のテストプログラムではスコアをチェックしているだけで、Canvasの表示結果は目視でチェックしている。
getImageDataなどを使ってCanvasの表示内容をチェックできそうだが、そこまでする気にはならない。
「asyncTest()内でメインループを止める処理を実行」は、ゲームの自動実行テストにいろいろと使えそうだが、clearIntervalなどが発行されるまでタイムラグがあることを考慮する必要がある。
スポンサーサイト



QUnit & jQuery でイベント起動処理のテストを行う

QUnitを使ったイベント起動処理のテスト方法について書く。
jQueryを使うことを前提とする。

1. 今回のテスト対象
簡単な例として、「四角形をクリックすると動く」だけのコードをテスト対象とする。
/* boxをクリックすると動く */
var mvb = {}; // namespace
/* 定数 */
mvb.con = {
  rootid: 'root', // rootdivのid
  boxid: 'box1', // boxのid
  boxtop: 20, // boxのcss top
  boxleft: 20, // boxのcss left初期値
  boxmvlen: 200, // boxの移動距離(px)
  boxclsnm: 'boxdiv', // boxのcss classname
  bgcol: 'rgb(51,153,255)' // boxの背景色
};
/* boxを移動 */
mvb.movebox = function() {
  var $box = $(this);
  var afterleft; // 移動後のleft
  if ($box.css('left') == mvb.con.boxleft + 'px') {
    afterleft = mvb.con.boxleft + mvb.con.boxmvlen;
  } else {
    afterleft = mvb.con.boxleft;
  }
  $box.animate({left: afterleft});
};
$(document).ready(function() {
  // boxを作成し、rootdivに追加
  var $box = $('<div/>').attr('id', mvb.con.boxid)
      .addClass(mvb.con.boxclsnm)
      .css('backgroundColor', mvb.con.bgcol)
      .css('top', mvb.con.boxtop).css('left', mvb.con.boxleft);
  $('#' + mvb.con.rootid).append($box);
  // イベント付与
  $box.click(mvb.movebox);
});

2. QUnit実行htmlファイル作成
テスト対象のコードがQUnit実行htmlファイル上で動くようにする。
そのため、今回の例では以下を追加している。
・テスト対象のコードが参照するCSSを記述
・テスト対象のコードが使用する要素<div id="root"></div>を記述
追加箇所を赤字にした。
なお、simpleAnime.jsがテストの対象コード、simpleAnimeTest.jsが以下で解説するテストコード。
<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>イベント起動処理のテスト</title>
  <style TYPE="text/css">
  .rootdiv {
    position: relative;
  }
  .boxdiv {
    display: block;
    position: absolute;
    width: 100px;
    height: 100px;
    border-style: solid;
    border-width: 2px;
    border-color: #808080;
  }
  </style>

  <link rel="stylesheet" href="./qunit/qunit.css" type="text/css" media="screen">
  <script type="text/javascript" src="jquery.js" charset="UTF-8"></script>
  <script type="text/javascript" src="simpleAnime.js" charset="UTF-8"></script>
  <script type="text/javascript" src="./qunit/qunit.js" charset="UTF-8"></script>
  <script type="text/javascript" src="simpleAnimeTest.js" charset="UTF-8"></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>
  <div id="root"></div>
</body>
</html>

3. テストコード作成
作成した以下のテストコードについて解説する。
/* simpleAnime.js のテスト
 * jquery.js を前提としている
 */
var timeoutID;
module('$(document).ready');
asyncTest('waif for ready', 1, function() {
  timeoutID = window.setInterval(function() {
    if ( $('#' + mvb.con.boxid).length > 0) {
      ok(true, 'box has appended.');
      window.clearTimeout(timeoutID);
      start();
    }
  }, 100);
});
test('boxdiv', 4, function() {
  var $box = $('#' + mvb.con.boxid);
  strictEqual($box.hasClass(mvb.con.boxclsnm), true, 'classname');
  equal($box.css('backgroundColor').replace(/\s/g, ''), mvb.con.bgcol,
      'backgroundColor');
  equal($box.css('top'), mvb.con.boxtop + 'px', 'css top');
  equal($box.css('left'), mvb.con.boxleft + 'px', 'css left');
});

module('mvb.movebox');
asyncTest('movebox 1', 1, function() {
  // boxの位置を初期値にする
  var $box = $('#' + mvb.con.boxid);
  $box.css('left', mvb.con.boxleft);
  $box.click();
  timeoutID = window.setInterval(function() {
    if ( $box.css('left') == (mvb.con.boxleft + mvb.con.boxmvlen) + 'px') {
      ok(true, 'box moved left.');
      window.clearTimeout(timeoutID);
      start();
    }
  }, 100);
});
asyncTest('movebox 2', 1, function() {
  var $box = $('#' + mvb.con.boxid);
  $box.click();
  timeoutID = window.setInterval(function() {
    if ( $box.css('left') == mvb.con.boxleft + 'px') {
      ok(true, 'box moved right.');
      window.clearTimeout(timeoutID);
      start();
    }
  }, 100);
});

3.1 $(document).ready のテスト
asyncTest('waif for ready', ...)で、$(document).readyで指定した処理が終わるまで待つ。
asyncTest()については、[QUnit] asyncTest() および stop() を簡単に解説 で解説している。
$(document).readyの処理が終わってからテストコードが動くようにするため、最後の処理が実行されることを確認してからstart()することが望ましい。
今回の例では「クリックイベントが付与されたこと」を確認するのが望ましいのだが、簡単にできそうにないので「四角形が追加されたこと」を確認している。
($box.data('events') でセットされているイベントハンドラを参照できるのだが、jQuery内部で使用しているデータでAPIとしては提供されていない)
その後のtest('boxdiv', ...)で、$(document).readyの処理結果をチェックしている。

3.2 クリックイベントのテスト
asyncTest('movebox 1', ...)およびasyncTest('movebox 2', ...)内でクリックイベントを発行して、イベント起動処理が終わるまで待つ。
$(document).readyと同様、最後の処理が実行されることを確認してからstart()することが望ましい。
今回の例では「右(または左)に動いたこと」をチェックするだけなので、asyncTest()内でテストが完結している。必要であれば後続に処理結果チェック用のtest()を追加する。

3.3 テストコード作成時の注意事項
asyncTest()およびtest()外に記述されたコードは、start()を待たずに即実行される。
そのため、テストコードはasyncTest()およびtest()内に記述すること。

以上。

<関連エントリ>
QUnit+jQueryで、チンチロリンゲーム自動実行テストプログラムを作った

[QUnit] asyncTest() および stop() を簡単に解説

QUnitでは、非同期テスト用のAPIとして asyncTest(), stop(), start() を提供している。
ある程度使い方がわかったので解説してみる。

1. asyncTest()
asyncTest()実行後は、start()が実行されるまで次のtest()またはasyncTest()を実行しない。
<asyncTest()の例>
  asyncTest('asyncTest', function() {
    setTimeout(function(){
      ok(true, 'asyncTest');
      start();
    }, 10);
  });
  test('after test', function() {
    ok(true, 'after test')
  });
実行結果は次のようになる。
asyncTest1.png

asyncTest()を使用しない場合、
  test('not asyncTest', function() {
    setTimeout(function(){
      ok(true, 'not asyncTest');
      start();
    }, 10);
  });
  test('after test', function() {
    ok(true, 'after test')
  });
実行結果は次のようになる。
asyncTest2.png
setTimeoutの結果を待たずにtest('after test', ...)が実行されるため、setTimeout内のテストがスキップされた状態になる。

2. stop()
asyncTest()と同様、stop()実行後も、start()が実行されるまで次のtest()またはasyncTest()を実行しない。
上記asyncTest()の例をstop()を使って書くと、
  test('stop test', function() {
    stop();
    setTimeout(function(){
      ok(true, 'stop test');
      start();
    }, 10);
  });
  test('after test', function() {
    ok(true, 'after test')
  });
となり、実行結果は次のようになる。
asyncTest3.png

3. asyncTest()およびstop()使用時の注意事項
asyncTest()もstop()も、次のtest()またはasyncTest()の実行を保留する。
しかし、test()またはasyncTest()外のコードは保留されずに実行される
例を示すと、
  var testval = 0;
  asyncTest('asyncTest', function() {
    setTimeout(function(){
      ok(true, 'testval = ' + testval);
      testval = 1;
      ok(true, 'testval = ' + testval);
      start();
    }, 10);
  });
  testval = 2;
  test('after test', function() {
    ok(true, 'testval = ' + testval);
  });
  testval = 3;
この実行結果は次のようになる。
asyncTest4.png
処理の実行順序が
asyncTest('asyncTest', ...) 実行でsetTimeout起動

testval = 2

testval = 3

10ミリ秒後にsetTimeout(...) が実行され、testval = 1 とstart()実行

test('after test', ...) 実行
となっていることがわかる。
これは、QUnitがtest()およびasyncTest()をキューイングして保留しているためで、キューイング対象外のコードは保留されずに実行される。

4. asyncTest()およびstop()を使用してできること
タイマー起動される処理、イベント起動処理(onLoadイベント含む)、サーバーと通信する処理などのテストができる。
次エントリで、QUnitを使ったイベント起動処理テストの例を書く予定。
(書きました → QUnit & jQuery でイベント起動処理のテストを行う

[QUnit]オブジェクトのダンプを取って内容を比較する

JavaScriptのテスト用プログラムを作ったので公開。
タイトルにはQUnitとあるが、ほかのツールでも使える。

[JavaScript]JSON的なダンプをとる関数を作ってみた
を参考にして、オブジェクトのダンプを取るプログラムを作成した。
objdump.js (文字コードはUTF-8)
ダンプを出力する関数 midump.objdump() の説明は以下のとおり。
/**
 * オブジェクトのダンプを出力する
 * @param {Object} obj ダンプ対象オブジェクト
 * @param {?number} dec numberを小数点以下何桁で四捨五入するか。
 *    四捨五入しない場合はnull
 * @param {boolean} linear 改行およびインデントせず、
 *    objectのmethodを出力しない場合true。それ以外の場合false
 * @param {boolean} escape 制御文字、ダブルクォートをエスケープする場合はtrue。
 *    それ以外の場合false。nullの場合のデフォルト値はture。
 *    linear == true の場合、
 *    ダブルクォートではなくシングルクォートがエスケープされる。
 * @param {?{html: boolean, dispf: boolean}} opt
 *    html: 改行を'<br />',スペースを'&nbsp;'で出力する場合true。
 *        改行を'\n',スペースを' 'で出力する場合false
 *    dispf: objectのmethodを出力する場合true。それ以外の場合false
 *    nullの場合のデフォルト値は全てtrueだが、linearの値が優先される。
 * @return {string} ダンプ結果
 */
midump.objdump = function(obj, dec, linear, escape, opt) {

テストコード用のコンパクトなダンプを出力するため、次の機能を作成した。
・1行ダンプ出力。(改行およびインデントせず、オブジェクトのメソッドを出力しない)
・numberを小数点以下何桁で四捨五入するかを引数で指定。

midump.objdump()を使った、QUnitでのテスト手順は以下のようになる。

1. オブジェクトの中身をダンプして予想されるテスト結果を作成
  midump.objdump(object, 四捨五入する小数点以下の桁, true, true)
でオブジェクトの中身をダンプする。

<ダンプするHTMLの例>
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8" />
  <title>オブジェクトの中身をダンプ</title>
  <script type="text/javascript" src="objdump.js" charset="UTF-8"></script>
  <script>
  var load = function() {
    // テスト対象のクラス
    var TestClass1 = function(arg1, arg2) {
      this.prop1 = [];
      for (var i = 0; i < 3; i++) {
        this.prop1[i] = new TestClass2(i, arg1);
      }
      this.prop2 = {};
      this.prop2.sub1 = arg2;
      this.prop2.sub2 = new TestClass2('sub2', arg2);
    };
    var TestClass2 = function(arg1, arg2) {
      this.prop3 = arg1;
      this.prop4 = arg2;
    };
    TestClass2.prototype.test = function() {
      return this.prop3;
    };
    
    var dumpdiv = document.getElementById('dump');
    dumpdiv.innerHTML = midump.objdump(new TestClass1(0.12345, 'b\n\'"'), 5, true, true);
  };
  </script>
</head>
<body onload="load();">
<div>dump result</div>
<div id="dump"></div>
</body>
</html>
このHTMLを実行すると、次のように出力される。
dump result
'{prop1:[{prop3:0,prop4:0.1235},{prop3:1,prop4:0.1235},{prop3:2,prop4:0.1235}],prop2:{sub1:"b\n\'"",sub2:{prop3:"sub2",prop4:"b\n\'""}}}'

このダンプ結果から、予想されるテスト結果は次のようになる。
// 予想される結果のダンプ
var expobjdump = '\'{prop1:[{prop3:0,prop4:0.1235},{prop3:1,prop4:0.1235},{prop3:2,prop4:0.1235}],prop2:{sub1:"b\n\'"",sub2:{prop3:"sub2",prop4:"b\n\'""}}}\'';
両端のシングルクォートが '\' になることに注意。(1行ダンプ出力結果がシングルクォートで囲われることと、エスケープ文字の関係上こうしている)

なお、1行ダンプ出力ではなく、見やすいダンプを出力したい場合は
dumpdiv.innerHTML = midump.objdump(new TestClass1(0.12345, 'b\n\'"'), 5, false, true, {html: true, dispf: true});
と書けばよい。

2. テストコードを作成
予想されるテスト結果とmidump.objdump()を使ってテストコードを作成する。
上記の例の場合、テストコードは以下のようになる。
    // テスト対象のクラス
    var TestClass1 = function(arg1, arg2) {
      this.prop1 = [];
      for (var i = 0; i < 3; i++) {
        this.prop1[i] = new TestClass2(i, arg1);
      }
      this.prop2 = {};
      this.prop2.sub1 = arg2;
      this.prop2.sub2 = new TestClass2('sub2', arg2);
    };
    var TestClass2 = function(arg1, arg2) {
      this.prop3 = arg1;
      this.prop4 = arg2;
    };
    TestClass2.prototype.test = function() {
      return this.prop3;
    };
    
    // 予想される結果のダンプ
    var expobjdump = '\'{prop1:[{prop3:0,prop4:0.1235},{prop3:1,prop4:0.1235},{prop3:2,prop4:0.1235}],prop2:{sub1:"b\n\'"",sub2:{prop3:"sub2",prop4:"b\n\'""}}}\'';

    // テスト対象のクラスと予想される結果とを比較
    var clsins = new TestClass1(0.12345, 'b\n\'"');
    test('test', function() {
      equal(midump.objdump(clsins, 5, true, false), expobjdump, 'compare clsins with expobj');
    });
比較する際のmidump.objdump()ではエスケープ処理をしないため、4番目の引数がfalseになることに注意。

このテストコードをQUnitで実行すればよい。

この方法で実際にテストしているのだが、HTMLをいじって出力し、ブラウザからコピ&ペーストしてテストコードを作成するので手間がかかる。
もっといい方法がありそうだ。

<関連エントリ>
[QUnit]deepEqualでクラスインスタンスとオブジェクトを比較する方法

[QUnit]deepEqualでクラスインスタンスとオブジェクトを比較する方法

この方法は、2011-05-16 commit版のQUnitで確認しています。
QUnit.equivの実装が変わるとdeepEqualをpassしなくなる恐れがありますので注意してください。

QUnitには、deepEqualというオブジェクトの比較に便利なassertionがある。
以下のように、あらかじめ用意した結果との比較が簡単にできる。
test('testfunc()のテスト', 1, function() {
  // 予想される結果
  var expobj = [
    {prop1: 1, prop2: 1},
    {prop1: ['a', 12, {a: null, b: 15}], prop2: null}
  ];

  var testobj = testfunc();
  deepEqual(testobj, expobj, 'compare testobj with expobj');
});

しかし、クラスインスタンスとオブジェクトを比較する場合、オブジェクトにメソッドとコンストラクタをセットしないとdeepEqualをpassしない。
そこで、メソッドとコンストラクタをセットするのに便利なプログラムを作成した。
setmethod.js(文字コードはUTF-8)
提供している関数はmiqtutl.setmethod()だけ。
  var rtn = miqtutl.setmethod(chkobj, targetobj);
で、chkobjのメソッドとコンストラクタををtargetobjにセットできる。

関数からはエラーメッセージの配列がreturnされるので、
  var rtn = miqtutl.setmethod(chkobj, targetobj);
  deepEqual(rtn, [], 'no error message');
とすることで、きちんとセットできたことを確認できる。
エラーメッセージは、メソッド付与対象のオブジェクトが存在しない場合や、メソッドと同名のプロパティが既に存在している場合などに出力される。
setmethod1.png
deepEqual(rtn, [])でリターン値をチェックすると、エラーの場合上のように表示される。

miqtutl.setmethod()を使って、以下のようにクラスインスタンスとオブジェクトとを比較できる。
// テスト対象のクラス
var TestClass1 = function(arg1, arg2) {
  this.prop1 = [];
  for (var i = 0; i < 3; i++) {
    this.prop1[i] = new TestClass2(i, arg1);
  }
  this.prop2 = {};
  this.prop2.sub1 = arg2;
  this.prop2.sub2 = new TestClass2('sub2', arg2);
};
var TestClass2 = function(arg1, arg2) {
  this.prop3 = arg1;
  this.prop4 = arg2;
};
TestClass2.prototype.test = function() {
  return this.prop3;
};

test('TestClass1のconstructorのテスト', 2, function() {
  // 予想される結果
  var expobj = {
    prop1: [{prop3: 0, prop4: 'a'}, {prop3: 1, prop4: 'a'},
        {prop3: 2, prop4: 'a'}],
    prop2: {sub1: 'b', sub2: {prop3: 'sub2', prop4: 'b'}}
  };
  // クラスインスタンスを生成し、expobjにクラスのメソッドとコンストラクタをセット
  var clsins = new TestClass1('a', 'b');
  var rtn = miqtutl.setmethod(clsins, expobj);
  deepEqual(rtn, [], 'no error message');
  // クラスインスタンスと予想される結果とを比較
  deepEqual(clsins, expobj, 'compare clsins with expobj');
});

特記事項
・miqtutl.setmethod()は、メソッドとコンストラクタをコピーしているのではなく、参照をセットしているだけ。
・メソッドをセットしてもプロパティの順序が異なるので、deepEqualはpassしてもDiffは出力される。
・再帰の深度が10になると例外がthrowされる。setmethod.jsのmaxDepthの値を変えることで、最大深度を変更できる。

以上。
予想される結果を作成するために、オブジェクトのダンプをテキスト出力するプログラムも作ったので、そのうち公開するかもしれない。
(公開しました → [QUnit]オブジェクトのダンプを取って内容を比較する

QUnitでのテストに使えそうなプログラム作成中

[QUnit]deepEqualでクラスインスタンスとオブジェクトを比較してハマる
でクラスインスタンスとオブジェクトをdeepEqualする方法を書いたのだが、比較対象オブジェクトにクラスメソッドをセットしないとdeepEqualをpassしない。

クラスメソッドをセットするだけなら、以下のようなテストプログラムを書けばいい。
var TestClass = function() {
  this.prop1 = 1;
  this.prop2 = 1;
};
TestClass.prototype.meth = function() {
  this.prop1++;
};

test('deepEqual class isntance and object', 2, function() {
  var clsins = new TestClass();
  var obj = {prop1: 1, prop2: 1};
  var errmsg = '';
  for (var prop in clsins) {
    if (typeof clsins[prop] == 'function') {
      if (obj[prop] != undefined) {
        errmsg = 'property [' + prop + '] already exists, so cannot set method.';
      } else {
        obj[prop] = clsins[prop];
      }
    }
  }
  obj.constructor = clsins.constructor;
  clsins.constructor = clsins.constructor;
  equal(errmsg, '', 'no error message');
  deepEqual(clsins, obj, 'deepEqual');
});
単純なクラスならこれでいいのだが、オブジェクトのプロパティや配列の中にクラスインスタンスがあるようなケースでは使えない。

せっかくなので、再帰的にオブジェクトや配列の中をたどって、比較対象オブジェクトにクラスメソッドをセットするプログラムを作成することにした。
動作確認はできたので、エラーケースのテストが終わったら公開するつもり。

[QUnit]deepEqualでクラスインスタンスとオブジェクトを比較してハマる

引き続きQUnitでテストしている。
QUnitにはdeepEqualというassertionがある。
配列やオブジェクトのメンバを再帰的に比較してくれるので役に立つ。

クラスのコンストラクタのテストで、以下のようなテストコードを作成した。
  var TestClass = function() {
    this.prop = 1;
  };
  test('TestClass', function(){
    var class1 = new TestClass();
    deepEqual(class1, {prop:1});
  });
メンバが同じオブジェクトなのに、deepEqualがfailedになった。しかもDiffが出ないので理由がわからない。

デバッガでたどって調べたところ、QUnit.equivの以下の箇所でfailedと判定されていた。
  // comparing constructors is more strict than using instanceof
  if ( a.constructor !== b.constructor) {
   return false;
  }
failedとなった理由は、同一クラスから生成されたインスタンスでないからだとわかった。

上記の箇所さえ通ればいいのではと思い、テストコードを変更
  var TestClass = function() {
    this.prop = 1;
  };
  test('TestClass', function(){
    var class1 = new TestClass();
    var object1 = {prop:1};
    object1.constructor = class1.constructor;
    deepEqual(class1, object1);
  });
だが再びfailed。理由はclass1.constructorが無いから。
class1.constructorは組み込みプロパティなので for ... in の対象にならず、QUnitでは抽出されない。

そこで、constructorプロパティをユーザー定義プロパティに上書きした。
  var TestClass = function() {
    this.prop = 1;
  };
  test('TestClass', function(){
    var class1 = new TestClass();
    var object1 = {prop:1};
    object1.constructor = class1.constructor;
    class1.constructor = class1.constructor;
    deepEqual(class1, object1);
  });
これで晴れてpassedになった。

めでたしめでたし・・・なのか?
QUnit.equivが変更されたらfailedになりそう。

<関連エントリ>
[QUnit]deepEqualでクラスインスタンスとオブジェクトを比較する方法
  クラスにメソッドがある場合、オブジェクトにメソッドもセットしないとdeepEqualをpassしない。
  オブジェクトのプロパティや配列中にあるクラスインスタンスを再帰的に探してメソッドを付与するプログラムを公開。

QUnitを使ってみる

昨日公開したプログラムを今更テストしている。
テストツールはQUnitを使うことにした。
今回初めて使うのだが、覚えることが少ないのですぐに使うことができた。

テスト起動用HTMLファイルを作るところでちょっと戸惑ったが、
ダウンロードしたフォルダの test\index.html をコピーして変更すればすぐできる。
変更する箇所は
    <script type="text/javascript" src="../qunit/qunit.js"></script>
の前にテスト対象プログラムを読み込む<script>タグを記述。
    <script type="text/javascript" src="test.js"></script>
    <script type="text/javascript" src="same.js"></script>
をテストプログラムを読み込む<script>タグに置き換える。
の二箇所だけ。

テストプログラムは、test()の中でAssertionを行う関数を記述するだけでいい。
AssertionのdeepEqual()は、オブジェクトや配列の中を再帰的にチェックしてくれるので
  deepEqual(diceins.camAngles_,
      [{x: 47, y: 35, z: 0}, {x: 47 + 90, y: 35, z: 0}, {x: 47, y: 35, z: 70}],
      'this.camAngles_');
のように使うことができて便利だ。
例外発生をチェックできるraises()もある。

以前ちょっと触ったJsUnitと比較すると、
・JsUnitのようにテストファイルを指定してRUNボタンを押すような手間が無い。HTMLファイルを起動するだけでQUnitのテストが実行できる。
・JsUnitでは「Test Functionを記述したhtmlは、testRunner.htmlと同一か配下のフォルダに格納しないと動かない」という制約が(自分の環境では)あったが、QUnitではそのような制約は無かった。

自分にとってはQUnitの方が使いやすいので、これからはこっちを使おう。
プロフィール

himax64

Author: 南西
30代後半の無職です。
就活もせずダラダラ生きてます。
作ったもの

最新記事
人気記事
検索フォーム
カテゴリ
月別アーカイブ
最新コメント
最新トラックバック
RSSリンクの表示
QRコード
QRコード
カウンター