script.aculo.usを読み解く

第9回 unittest.js(前編)

この記事を読むのに必要な時間:およそ 9 分

Test.Unit.Logger

Test.Unit.Loggerクラスは,テストの結果を表組みにして表示するためのクラスです。

0070:var Test = {}
0071:Test.Unit = {};
0072:
0073:// security exception workaround
0074:Test.Unit.inspect = Object.inspect;
0075:

70,71行目で,Testクラスを作り,その下にTest.Unitクラスを作ります。

74行目で,Prototype.jsのinspectメソッドに対応するようにします。

0076:Test.Unit.Logger = Class.create();
0077:Test.Unit.Logger.prototype = {
0078:  initialize: function(log) {
0079:    this.log = $(log);
0080:    if (this.log) {
0081:      this._createLogTable();
0082:    }
0083:  },

78~83行目のinitializeは,インスタンスの初期化を行う関数です。引数にログを出力する要素のDOM idを取ります。

79行目で,ログを出力する要素を取得します。取得できない場合はログは出力されません。

80行目で,その要素の内部に表を作ります。

0084:  start: function(testName) {
0085:    if (!this.log) return;
0086:    this.testName = testName;
0087:    this.lastLogLine = document.createElement('tr');
0088:    this.statusCell = document.createElement('td');
0089:    this.nameCell = document.createElement('td');
0090:    this.nameCell.className = "nameCell";
0091:    this.nameCell.appendChild(document.createTextNode(testName));
0092:    this.messageCell = document.createElement('td');
0093:    this.lastLogLine.appendChild(this.statusCell);
0094:    this.lastLogLine.appendChild(this.nameCell);
0095:    this.lastLogLine.appendChild(this.messageCell);
0096:    this.loglines.appendChild(this.lastLogLine);
0097:  },

84~97行目のstartは,表組みのテスト結果の1行分を作る関数です。引数にテスト名をとります。表はこの図のようになります。

テーブルの様子

画像

0098:  finish: function(status, summary) {
0099:    if (!this.log) return;
0100:    this.lastLogLine.className = status;
0101:    this.statusCell.innerHTML = status;
0102:    this.messageCell.innerHTML = this._toHTML(summary);
0103:    this.addLinksToResults();
0104:  },

98~104行目のfinishは,statusCellとmessageCellにテスト結果を書き込む関数です。

103行目では,後述のaddLinksToResultsで,クリックするとそのテストを再試行するようにします。

0105:  message: function(message) {
0106:    if (!this.log) return;
0107:    this.messageCell.innerHTML = this._toHTML(message);
0108:  },

105~108行目のmessageは,messageCellにメッセージを書き込む関数です。内部的に,'実行中...'などと表示するのに使われます。

0109:  summary: function(summary) {
0110:    if (!this.log) return;
0111:    this.logsummary.innerHTML = this._toHTML(summary);
0112:  },

109~112行目のsummaryは,logsummaryにテスト全体の結果の要約を書き込む関数です。

0113:  _createLogTable: function() {
0114:    this.log.innerHTML =
0115:    '<div id="logsummary"></div>' +
0116:    '<table id="logtable">' +
0117:    '<thead><tr><th>Status</th><th>Test</th><th>Message</th></tr></thead>' +
0118:    '<tbody id="loglines"></tbody>' +
0119:    '</table>';
0120:    this.logsummary = $('logsummary')
0121:    this.loglines = $('loglines');
0122:  },

113~122行目の_createLogTableは,表組みのテーブルを作る関数です。動的にテーブルを作るために,innerHTMLに書き込む方法をとっているのは,DOM操作で作ろうとするとブラウザ間の仕様の違いに悩まされることになるからです(過去に解説したbuilder.jsでもこの問題への対処がありました⁠⁠。

0123:  _toHTML: function(txt) {
0124:    return txt.escapeHTML().replace(/\n/g,"<br/>");
0125:  },

123~125行目の_toHTMLは,引数の文字列をHTMLの文字列表現にする関数です。Prototype.jsのescapeHTMLを使います。

0126:  addLinksToResults: function(){ 
0127:    $$("tr.failed .nameCell").each( function(td){ // todo: limit to children of this.log
0128:      td.title = "Run only this test"
0129:      Event.observe(td, 'click', function(){ window.location.search = "?tests=" + td.innerHTML;});
0130:    });
0131:    $$("tr.passed .nameCell").each( function(td){ // todo: limit to children of this.log
0132:      td.title = "Run all tests"
0133:      Event.observe(td, 'click', function(){ window.location.search = "";});
0134:    });
0135:  }
0136:}
0137:

126~136行目のaddLinksToResultsは,失敗したテストの表組みのセルをクリックするとそのテストを再試行するように,onClickイベントにハンドラを追加する関数です。このようにテストの一部分だけ実行するには,Test.Unit.Runnerで説明するとおり,クエリパラメータのtestsに実行したいテスト名を記述して,ページを読み込みます。

131~135行目で,同様に,成功したテストのセルをクリックすると,テスト全てを再試行するようにします。

著者プロフィール

源馬照明(げんまてるあき)

名古屋大学大学院多元数理科学研究科1年。学部生のときにSchemeの素晴らしさを知ったのをきっかけに,関数型言語の世界へ。JavaScriptに,ブラウザからすぐに試せる関数型言語としての魅力と将来性を感じている。

ブログ:Gemmaの日記