前回の続き。
テスト駆動開発の考え方は、なんとなく分かった。
だが、具体的なことはまだ何も分かっていない。
その考え方をどのように実現するのか、という部分。
テスト駆動開発の考え方は分かったし、本当にそれが実現できるなら素晴らしいと思う。だが本当にそんなことを出来るのだろうか。
本当に、自動でテスト出来るのか?
本当に、リグレッションを防止できのか?
机上の空論ではなく本当に、メリットを享受できるのか。
ということで、JavaScriptのテスティングフレームワークを実際に使ってみる。
QUnitの準備
今回はQUnitを使うことにした。
ざっと調べたところ、後発のmochaなどのほうがいいらしいが、さっぱり理解できなかった。
Node.jsが前提になっているような記事も多く、今の自分には無理だと判断。
背伸びせず、簡単、シンプルだとされているQUnitにした。
QUnitはもともとjQueryのテストのために開発されたそうだが、現在はjQueryとは無関係に使用できる。
必要なJavaScriptファイルとCSSファイルをCDNで読み込む。
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>QUnit</title> <link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.22.0.css"> </head> <body> <div id="qunit"></div> <div id="qunit-fixture"></div> <script src="http://code.jquery.com/qunit/qunit-1.22.0.js"></script> <script src="test.js"></script> </body> </html>
これで利用できる。後は、テスト用のJavaScriptファイル(上記の例だとtest.js)に、内容を書き込んでいけばいい。
QUnitの使い方
testという関数で記述し、第一引数にそのテストケースの名前、第二引数に内容を書く。
最も基本的な書き方
testの第二引数の無名関数のなかに、ok関数を書く。
その第一引数に、確認するコードを書く。
第二引数に、ブラウザに表示させるメッセージを書く。
ok関数は、第一引数の値がtrueであるかを判定するための関数。
test("okの挙動を確かめるテスト", function() { ok(false, "falseのok関数"); // テストは通らない ok(true, "trueのok関数"); // テストが通る ok(1 === '1', "同値演算子のok関数"); // テストは通らない ok(1 == '1', "等価演算子のok関数"); // テストが通る });
上記の内容を実行すると、ブラウザにこのように表示される。
なお、testやokの前にQUnit.をつけても動く。名前空間の汚染を考えれば、このほうがよさそうだ。以下、この書き方で統一していく。
// 先ほどと全く同じ結果になる QUnit.test("okの挙動を確かめるテスト", function() { QUnit.ok(false, "falseのok関数"); // テストは通らない QUnit.ok(true, "trueのok関数"); // テストが通る QUnit.ok(1 === '1', "同値演算子のok関数"); // テストは通らない QUnit.ok(1 == '1', "等価演算子のok関数"); // テストが通る });
equal,deepEqua,throws
ok関数は、アサートの一種だという。 アサート、というのがよく分からないが、条件や要件のことだろう。
QUnitには、ok以外にもいくつかアサートがある。
equal関数は、第一引数と第二引数の値が一致するか判定する。第三引数にメッセージ。
第一引数にチェックすべき値を入力し、期待される結果を第二引数に入れる。
比較は、等価演算(自動で型変換をする)で行う。同値演算(型変換をしない)は、strictEqual関数で行う。
QUnit.test("テスト", function() { // 以下は通る QUnit.equal(false, false, "equal関数"); QUnit.equal(33, 33, "equal関数"); QUnit.equal(1, '1', "equal関数"); // 以下は通らない QUnit.equal(0, '3', "equal関数"); QUnit.equal(33, 34, "equal関数"); QUnit.strictEqual(1, '1', "strictEqualequal関数"); });
deepEqual関数は、オブジェクトや配列を比較する。
内容が完全に一致していないと、通らない。
QUnit.test('名前', function(){ var obj1 = { foo: "bar" }; QUnit.deepEqual(obj1, { foo: 'bar' }, "最初のアサート"); // 通る obj1.hoge = 'hoge'; QUnit.deepEqual(obj1, { foo: "bar" }, "2回めのアサート"); // 通らない QUnit.deepEqual(obj1, { // 通る hoge: "hoge", foo: "bar" }, "3回めのアサート"); });
throws関数は、第一引数に渡した関数が例外を投げるかどうかを調べる。
QUnit.test('throws', function(){ QUnit.throws( function(){ throw 'error' }, 'アサート' ); // 通る QUnit.throws( function(){}, 'アサート2' ); // 通らない });
stopとstart
test関数のなかでstop関数を使うと、処理を停止できる。その後、start関数を使うことで、処理が再開される。
下記の例だと、テスト関数開始の2秒後に、ok関数が実行される。
QUnit.test("stop", function() { QUnit.stop(); setTimeout(function(){ QUnit.start(); QUnit.ok(1 == "1", "stopのテスト"); }, 2000); });
この例だと何の意味もないが、例えば、非同期処理のテストなどで、すぐにはアサートを実行したくない、コールバックの処理が終わってからテストしたい、という状況などで利用できる。