JsTestDriver の使い方をメモする。
JsTestDriver とは、 Google が開発してるオープンソースの JavaScript 用テスティングフレームワークのこと。
#環境
##OS
Windows7 64bit
##Java
1.7.0_25
##JsTestDriver
1.3.5
#JsTestDriver のインストール
ここ から JsTestDriver-x.x.x.jar
をダウンロードして任意のフォルダに配置する。
仮に jar を配置したフォルダのパスを %JSTESTDRIVER_HOME%
とする。
#テストを実行する
JsTestDriver でテストするときの手順はおおまかには以下の通り。
- JsTestDriver サーバを起動する
- テストしたいブラウザを JsTestDriver サーバに接続する
- テストを実行する
##JsTestDriver サーバを起動する
コマンドプロンプトを開き、以下のコマンドを実行する。
>java -jar %JSTESTDRIVER_HOME%\JsTestDriver-x.x.x.jar --port 4224
サーバが 4224 ポートで起動する(4224 ポートは JsTestDriver を使うときの慣例らしい)。
##テストしたいブラウザを JsTestDriver サーバに接続する
とりあえず Chrome で接続する。
Chrome を起動し、 http://localhost:4224
にアクセスする。
テストする時のページのDTD を「移行型」と「厳密型」のどちらにするかを選択する。
選択すると、以下のページに移動する。ブラウザの準備はこれで OK。
##テストを実行する
###フォルダ構成
D:\tmp\JsTestDriver
│ jsTestDriver.conf
├─src
│ TestTarget.js
└─test
TestTargetTest.js
###各ファイルの内容
function targetMethod(x, y) {
return x + y;
}
TestCase('TestTarget Test', {
'test targetMethod': function() {
// setup
var expected = 51;
// exercise
var actual = targetMethod(11, 40);
// verify
assertEquals(expected, actual);
}
});
server: http://localhost:4224
load:
- src/*.js
- test/*.js
###実行方法
コマンドプロンプトを開き、 jsTestDriver.conf
のあるフォルダに移動して次のコマンドを実行する。
※jsTestDriver.conf
があるフォルダまでのパスに日本語が含まれるとエラーになる。
>java -jar %JSTESTDRIVER_HOME%\JsTestDriver-x.x.x.jar --tests all
setting runnermode QUIET
.
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (0.00 ms)
Chrome 29.0.1547.76 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (0.00 ms)
###注意点
####テスト関数は、名前が test
で始まっている必要がある。
TestCase('TestTarget Test', {
// 実行される
'test function': function() {
jstestdriver.console.log('test function');
},
// 実行されない
'not test function': function() {
jstestdriver.console.log('not test function');
}
});
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (1.00 ms)
Chrome 29.0.1547.76 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (1.00 ms)
TestTarget Test.test function passed (1.00 ms)
[LOG] test function
####テスト関数名には日本語が使えるが、実行時に文字化けする
TestCase('TestTarget Test', {
'test 日本語': function() {
jstestdriver.console.log('test 日本語');
}
});
Total 1 tests (Passed: 1; Fails: 0; Errors: 0) (0.00 ms)
Chrome 29.0.1547.76 Windows: Run 1 tests (Passed: 1; Fails: 0; Errors 0) (0.00 ms)
TestTarget Test.test ??{?? passed (0.00 ms)
[LOG] test ??{??
実行はできるけど、文字化けしてしまう。
テスト名は日本語で書きたいなぁ。。。
#その他使い方
##コンソール出力
console
はブラウザによっては対応していないものがあるので、 JsTestDriver を使うときは JsTestDriver が提供してるコンソール出力用 API を使うのが良い。
具体的には、 jstestdriver.console
というオブジェクトを使う。
log
や info
、 debug
といった関数が用意されてる。
TestCase('TestTarget Test', {
'test console': function() {
var console = jstestdriver.console;
console.log('log message');
console.debug('debug message');
console.info('info message');
console.warn('warn message');
console.error('error message');
}
});
[LOG] log message
[DEBUG] debug message
[INFO] info message
[WARN] warn message
[ERROR] error message
C の printf 的な使い方もできる。
TestCase('TestTarget Test', {
'test console': function() {
var string = 'string message';
var obj = {
string: 'Name',
num : 10,
bool : true,
und : undefined,
nul : null,
func : function() {
alert('hoge');
}
};
var console = jstestdriver.console;
console.log('string = %s', string);
console.log('obj = %o', obj);
}
});
[LOG] string = string message
[LOG] obj = {"string":"Name","num":10,"bool":true,"nul":null}
%s
で文字列形式、 %o
でオブジェクトを JSON に変換した形式で出力できる(undefined
と関数は出力されない)。
##事前処理・事後処理を実装する
JUnit の setUp
と tearDown
メソッドに該当するもの。
ずばりその名前で関数を定義すれば、各テストの前後で実行される。
TestCase('TestTarget Test', {
setUp: function() {
log('setUp');
},
tearDown: function() {
log('tearDown');
},
'test 1': function() {
log('test 1');
},
'test 2': function() {
log('test 2');
}
});
function log(msg) {
jstestdriver.console.log(msg);
}
TestTarget Test.test 1 passed (0.00 ms)
[LOG] setUp
[LOG] test 1
[LOG] tearDown
TestTarget Test.test 2 passed (0.00 ms)
[LOG] setUp
[LOG] test 2
[LOG] tearDown
各テストメソッドごとに、 setUp()
関数と tearDown()
関数が呼ばれる。
##各テスト関数で共通して使用する値を用意する
各テストで共通して使用したい値がある場合は、 setUp()
関数内で this
にプロパティを追加すればいい。
var cons = jstestdriver.console
TestCase('TestTarget Test', {
setUp: function() {
this.value = 'common value';
},
'test 1': function() {
cons.log('test 1 : this.value = %s', this.value);
},
'test 2': function() {
cons.log('test 2 : this.value = %s', this.value);
}
});
TestTarget Test.test 1 passed (0.00 ms)
[LOG] test 1 : this.value = common value
TestTarget Test.test 2 passed (0.00 ms)
[LOG] test 2 : this.value = common value
##1つの js ファイルに複数の TestCase を書く
JUnit4 の Enclosed みたいなイメージ。
var cons = jstestdriver.console;
TestCase('TestCase 1', {
'test 1': function() {
cons.log('test 1');
}
});
TestCase('TestCase 2', {
'test 2': function() {
cons.log('test 2');
}
});
Total 2 tests (Passed: 2; Fails: 0; Errors: 0) (1.00 ms)
Chrome 29.0.1547.76 Windows: Run 2 tests (Passed: 2; Fails: 0; Errors 0) (1.00 ms)
TestCase 1.test 1 passed (1.00 ms)
[LOG] test 1
TestCase 2.test 2 passed (0.00 ms)
[LOG] test 2
問題なく動く。事前処理が同じものでまとめるとコードが見やすくなるかな。
##テスト用の DOM を用意する
テストコード中に特殊なコメントを記述することで、テストでのみ使える DOM を用意することができる。
###DOM オブジェクトを作成する
TestCase('TestCase 1', {
'test': function() {
/*:DOC dom = <input value="test-value" />*/
var value = this.dom.getAttribute('value')
jstestdriver.console.log('dom.value = %s', value);
}
});
[LOG] dom.value = test-value
/*:DOC <変数名> = <HTMLタグ>*/
テスト実行時にコメント行を通過すると、以後 this.<変数名>
で <HTMLタグ>
に指定したタグの DOM オブジェクトを取得できるようになる。
####コメント行の前では DOM オブジェクトは取得できない
コメント行が処理される前だと、 DOM オブジェクトは生成されないので注意。
TestCase('TestCase 1', {
'test': function() {
jstestdriver.console.log('dom = %s', this.dom);
/*:DOC dom = <input />*/
}
});
[LOG] dom = undefined
####各テスト関数で生成した DOM オブジェクトはその関数内でのみ有効
各テスト関数内で生成された DOM は、その関数内でのみ使用可能で、他のテスト関数からは参照できない。
var cons = jstestdriver.console;
TestCase('TestCase 1', {
'test': function() {
cons.info('test1');
/*:DOC dom = <input />*/
cons.log('dom = %s', this.dom);
},
'test2': function() {
cons.info('test2');
cons.log('dom = %s', this.dom);
}
});
TestCase 1.test passed (0.00 ms)
[INFO] test1
[LOG] dom = [object HTMLInputElement]
TestCase 1.test2 passed (0.00 ms)
[INFO] test2
[LOG] dom = undefined
####各テスト関数から参照できる DOM オブジェクトを用意する
各テスト関数から共通で参照したい DOM オブジェクトがある場合は、 setUp()
関数にコメントを書けばいい。
var cons = jstestdriver.console;
TestCase('TestCase', {
setUp: function() {
/*:DOC dom = <input value="common-value" />*/
},
'test1': function() {
cons.info('test 1');
cons.log(this.dom.getAttribute('value'));
},
'test2': function() {
cons.info('test 2');
cons.log(this.dom.getAttribute('value'));
}
});
TestCase.test1 passed (0.00 ms)
[INFO] test 1
[LOG] common-value
TestCase.test2 passed (0.00 ms)
[INFO] test 2
[LOG] common-value
####複数の DOM を作成可能
1つのコメントの中で、複数のタグを記述できる。
TestCase('TestCase', {
'test': function() {
/*:DOC dom = <input value="test-value-1" /><input value="test-value-2" />*/
var children = this.dom.childNodes;
for (var i=0; i<children.length; i++) {
jstestdriver.console.log('childNodes[%d].value = %s', i, children[i].getAttribute('value'));
}
}
});
[LOG] childNodes[0].value = test-value-1
[LOG] childNodes[1].value = test-value-2
###ブラウザにDOMを追加する
TestCase('TestCase', {
'test': function() {
/*:DOC += <input id="test-dom" value="test-value" />*/
var value = document.getElementById('test-dom').getAttribute('value')
jstestdriver.console.log('value = %s', value);
}
});
[LOG] value = test-value
/*:DOC += <HTMLタグ>*/
他のテスト関数から参照できないなどの動作は DOM オブジェクトを作成する場合と同じ。
#参考