script.aculo.usを読み解く

第9回 unittest.js(前編)

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

Test.Unit.Runner

Test.Unit.Runnerは,テストを順番に実行するクラスです。ライブラリの利用者はこのクラスの引数にテスト全体を記述します。例えば以下のようになります。setupにはテスト前の処理,teardownにはテスト後の処理を書きます。

0001:new Test.Unit.Runner({
0002:  setup: function() {},
0003:  teardown: function () {},
0004:  testAssertEqual: function() { with(this) {
0005:    assertEqual(0, 0);
0006:    
0007:    assertEqual(0,'0');
0008:    assertEqual(65.0, 65);
0009:    
0010:    assertEqual("a", "a");
0011:    
0012:    assertNotEqual(0, 1);
0013:    assertNotEqual("a","b");
0014:  }}
0015:})  

それではコードに戻りましょう。

0138:Test.Unit.Runner = Class.create();
0139:Test.Unit.Runner.prototype = {
0140:  initialize: function(testcases) {
0141:    this.options = Object.extend({
0142:      testLog: 'testlog'
0143:    }, arguments[1] || {});
0144:    this.options.resultsURL = this.parseResultsURLQueryParameter();
0145:    this.options.tests      = this.parseTestsQueryParameter();
0146:    if (this.options.testLog) {
0147:      this.options.testLog = $(this.options.testLog) || null;
0148:    }
0149:    if(this.options.tests) {
0150:      this.tests = [];
0151:      for(var i = 0; i < this.options.tests.length; i++) {
0152:        if(/^test/.test(this.options.tests[i])) {
0153:          this.tests.push(new Test.Unit.Testcase(this.options.tests[i], testcases[this.options.tests[i]], testcases["setup"], testcases["teardown"]));
0154:        }
0155:      }
0156:    } else {
0157:      if (this.options.test) {
0158:        this.tests = [new Test.Unit.Testcase(this.options.test, testcases[this.options.test], testcases["setup"], testcases["teardown"])];
0159:      } else {
0160:        this.tests = [];
0161:        for(var testcase in testcases) {
0162:          if(/^test/.test(testcase)) {
0163:            this.tests.push(
0164:               new Test.Unit.Testcase(
0165:                 this.options.context ? ' -> ' + this.options.titles[testcase] : testcase, 
0166:                 testcases[testcase], testcases["setup"], testcases["teardown"]
0167:               ));
0168:          }
0169:        }
0170:      }
0171:    }
0172:    this.currentTest = 0;
0173:    this.logger = new Test.Unit.Logger(this.options.testLog);
0174:    setTimeout(this.runTests.bind(this), 1000);
0175:  },

140~175行目のinitializeは,インスタンスの初期化を行う関数です。引数のtestcasesに,ハッシュテーブル(キーにテスト名,値にテスト内容)を取ります。2番めの引数にオプションを取ることができます。テスト名は,名前が'test'で始まっている必要があります。

以下のオプションがあります。

testLog
結果を出力する要素のDOM idです。デフォルトは'testlog'です。
resultsURL
クエリパラメータresultsURLから与えます。結果の送信先のURLです。
tests
クエリパラメータtestsから与えます。引数で与えたtestcasesの中から,実行したいテスト名をカンマ区切りで指定します。
test
引数で与えたtestcasesの中から,実行したいテスト名を1つ指定します。
context
有効にすると,次のtitlesのオプションが使われます。
titles
テストのそれぞれにタイトルをつけることができます。キーにテスト名,値にタイトルのハッシュテーブルを与えます。

144行目で,クエリパラメータresultsURLから値を取りだします。parseResultsURLQueryParameterは後述します。

145行目で,クエリパラメータtestsから値を取りだします。parseTestsQueryParameterは後述します。

146行目で,ログの出力先になる要素を取得します。取得できなかったら,ログは出力されません。

149~156行目で,options.testsが指定されていたら,testcasesの中から,指定されたテストたちだけを加えます。テスト名は'test'で始まっている必要があります。Test.Unit.Testcaseは,後述するように,引数に,テスト名,テスト内容,テスト前の処理,テスト後の処理を取ります。

157行目で,options.testが設定されていたら,testcasesの中から,そのテストだけを加えます。

159~170行目で,何も設定がなければ,testcasesの全てのテストを加えます。テスト名は'test'で始まっている必要があります。

172行目で,this.currentTestは,現在実行中のテストが全体の何番めにあたるかを示します。まずは0にします。後述のrunTestsの内部で管理されます。

173行目で,Test.Unit.Loggerのインスタンスを作って,ログの出力先にします。

174行目で,タイマーで1000ミリ秒後にrunTestsを呼び,テストを開始します。

0176:  parseResultsURLQueryParameter: function() {
0177:    return window.location.search.parseQuery()["resultsURL"];
0178:  },

176~178行目のparseResultsURLQueryParameterは,ブラウザのアドレス欄のクエリパラメータから'resultsURL'の値を取り出す関数です。このアドレスに結果がAjaxで送信されます。

0179:  parseTestsQueryParameter: function(){
0180:    if (window.location.search.parseQuery()["tests"]){
0181:        return window.location.search.parseQuery()["tests"].split(',');
0182:    };
0183:  },

179~183行目のparseTestsQueryParameterは,ブラウザのアドレス欄のクエリパラメータから'tests'の値を取り出す関数です。この値に,実行したいテスト名をカンマ区切りで記述することで,スクリプトを書き換えずに,実行するテストを選べます。

著者プロフィール

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

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

ブログ:Gemmaの日記