実践TDD! テスト駆動開発入門
こんにちは、斉藤です。
前回のブログをさぼっていたので、あっというまに次のブログの日が来てしまいました。
最近、テスト駆動開発入門(ケントベック著)という本を読んでみて、これは!と思ったので、この開発方法の実践をしてみたいと思います。
今回はQUnitというJavaScriptのユニットテストフレームワークを使った方法でのご紹介です。
http://qunitjs.com/
* テスト駆動開発(TDD)とは?
ユニットテストを常に書きながら、プログラムを開発していくスタイルのことです。
ユニットテストを先に書くので、プログラムはそれが通るように開発することが求められます。
具体的な開発のサイクル:
1. テストを作成する(表現し たいことを確認するテストを作る。)
2. テストをパスする(1で作ったテストをパスする実装を行う。仮実装でも構わない。)
3. リファクタリングを行う(テストを増やし、正しい実装に変更する。)
メリット:
開発終了時には、ユニットテストレベルでの品質保証ができている
常にユニットテストを通すことを目標とするので、メソッド単位でのデグレが起きにくい
デメリット:
ユニットテストを書きながらの開発を行うため、その分の時間がかかる
となっています。実際にどんなことをやるかは後ほど触れていきます。
それでは、始めていきましょう!
* QUnit導入
まずはQUnitを使うべく、以下のHTMLとJSを用意しました。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit Example</title>
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.10.0.css">
</head>
<body>
<div id="qunit"></div>
<script src="http://code.jquery.com/qunit/qunit-1.10.0.js"></script>
<script src="tests.js"></script>
</body>
</html>
tests.js
test( "test hello", function() {
QUnit.equal(1, 1, "1=1");
});
また環境は以下の通りです。
OS: Mac OS X 10.7.5
ブラウザ: Chrome 24.0
これで、ユニットテストを使う環境が揃いました!
ユニットテストや、QUnitについての詳しい解説は他に譲るとして、これをベースにテスト駆動開発を行っていきます。
* 何を作る?
開発するテーマが無いと困るので、冒頭の書籍に倣って、以下の通貨を取り扱うためのプログラムを書いていきたいと思います。
お金を表すオブジェクト
乗法を表現するメソッド
お金同士を比較する方法
異なる通貨の表現
* お金を表すオブジェクト
テスト駆動開発では、先にテストを用意します。
そのため、まずお金を表すオブジェクトのためのテストを用意します。
tests.js
test( "testGetMoneyObject", function() {
var oneMoney = new Money();
QUnit.equal(oneMoney.amount, 1, "Get 1 money");
});
お金を表すため、オブジェクトMoneyとその数量amountを作ろうと思い、それを確認するテストを用意しました。
しかしこのままでは、エラーが表示されてしまいます。
これをパスするために、実際にそのクラスを作ります。
money.js
function Money(){
this.amount = 1;
};
JSでクラスを表す方法は色々ありますが、今回はシンプルにこの形で書いていくことにしました。テストをパスするために、仮実装としてamountプロパティには1を入れてあります。
index.htmlもこのクラスを読み込むように、scriptタグを追加します。
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>QUnit</title>
<link rel="stylesheet" href="http://code.jquery.com/qunit/qunit-1.10.0.css">
</head>
<body>
<div id="qunit"></div>
<script src="http://code.jquery.com/qunit/qunit-1.10.0.js"></script>
<script src="money.js"></script>
<script src="tests.js"></script>
</body>
</html>
とりあえず、書いたテストはパスします。
しかし、これならどうでしょうか。
tests.js
test( "testGetMoneyObject", function() {
var oneMoney = new Money();
QUnit.equal(oneMoney.amount, 1, "Get 1 money");
var fiveMoney = new Money();
QUnit.equal(fiveMoney.amount, 5, "Get 5 money");
});
二つ目のテストで落ちますね。
amountプロパティに定数を入れているので当然ですが。。。
これはオブジェクトを生成する際に、amountプロパティに代入するように出来れば良いですね。
test.js
test( "testGetMoneyObject", function() {
var oneMoney = new Money(1);
QUnit.equal(oneMoney.amount, 1, "Get 1 money");
var fiveMoney = new Money(5);
QUnit.equal(fiveMoney.amount, 5, "Get 5 money");
});
これに対応して、money.jsを変更します。
money.js
function Money(amount){
this.amount = amount;
};
これで、1円や5円を表すことが出来ます!
* 乗法を表現するメソッド
次にお金が複数あることを表現するテストを用意したいと思います。
tests.js
test( "testGetMoneyObject", function() {
var oneMoney = new Money(1);
QUnit.equal(oneMoney.amount, 1, "Get 1 money");
var fiveMoney = new Money(5);
QUnit.equal(fiveMoney.amount, 5, "Get 5 money");
});
test( "testTimes", function() {
var oneMoney = new Money(1);
oneMoney.times();
QUnit.equal(oneMoney.amount, 5, "Get 5 money");
});
testTimesというテストを用意しました。
これはまだtimesメソッドが無いのでパスしません。
新しく、そのメソッドを用意します。
money.js
function Money(amount){
this.amount = amount;
this.times = function() {
this.amount *= 5;
}
};
これでパスするようにはなりましたが、仮実装のため、"5円"を作ることしか出来ません。
これをリファクタリングしましょう。
test.js
test( "testGetMoneyObject", function() {
var oneMoney = new Money(1);
QUnit.equal(oneMoney.amount, 1, "Get 1 money");
var fiveMoney = new