どんなにすぐれたプログラマも、間違いを犯します。 よいプログラマとそうでないプログラマの違いは、 よいプログラマはテストを行って間違いをできるだけ早く発見してしまうことです。 テストをするのが早ければ早いほど間違いを発見しやすくなり、 またそれを修正しやすくなります。 リリース直前までテストを先延ばしにしておくことが非常に問題であるのはこのためです。 そんなことをすると、すべてのエラーを発見しきることができず、 発見したエラーを修正することも非常に難しくなります。結局は、 トリアージを行ってどのエラーに対応するかを判断しなければならなくなります。 なぜならすべてのエラーを完全に修正することは不可能だからです。
PHPUnit を使用したテストは、全体としてはあなたがこれまでに行ってきたことと同じです。 ただ、そのやり方が違うだけです。それは、テスト つまりあなたのプログラムが期待通りにふるまうことを調べることと 総合テスト つまり実行可能なコード片がソフトウェアの各部分 (部品) を自動的にテストすることとの違いになります。実行可能なコード片のことを、 単体テスト (unit test) と呼びます。
この章では、単純な print
ベースのテストコードをもとにして完全な自動テストに書き換えていきます。
PHP 組み込みの array
をテストするように頼まれたとしましょう。このオブジェクトの機能のひとつに、
関数 sizeof() があります。新しく作成された配列では、
sizeof() 関数は 0 を返すはずです。
そして要素を 1 つ追加すると sizeof() は
1 を返すようになるはずです。テストしたい内容を
例1.1「Array および sizeof() のテスト」
に示します。
例1.1 Array および sizeof() のテスト
<?php
$fixture = array();
// $fixture は空のはずです。
$fixture[] = 'element';
// $fixture はひとつの要素を含むはずです。
?>
期待通りの結果が得られているかどうかを調べるためのいちばん単純な方法は、
要素を追加する前と後に sizeof() の結果を表示することです
(例1.2「print を使用した Array および sizeof() のテスト」 を参照ください)。
それぞれ 0 および 1 が得られたら、
array および sizeof()
が期待通りに動作していることになります。
例1.2 print を使用した Array および sizeof() のテスト
<?php
$fixture = array();
print sizeof($fixture) . "\n";
$fixture[] = 'element';
print sizeof($fixture) . "\n";
?>
0 1
このテストは、成功したかどうかの判断を (出力結果を見て)
手動で行わなければなりません。今度は、この判断を自動でできるようにしてみましょう。
例1.3「期待値と実際の値を比較することによる Array および sizeof() のテスト」 では、
期待される結果と実際の結果をコード中で比較して、もしそれらの値が等しければ
ok と表示します。もし not ok
と表示された場合は、どこかがおかしいということがわかります。
例1.3 期待値と実際の値を比較することによる Array および sizeof() のテスト
<?php
$fixture = array();
print sizeof($fixture) == 0 ? "ok\n" : "not ok\n";
$fixture[] = "element";
print sizeof($fixture) == 1 ? "ok\n" : "not ok\n";
?>
ok ok
今度は、相違があった際に例外を発生させる関数を用意して、 期待値と実際の値を比較する処理を抽出してみましょう (例1.4「アサーション関数を使用した Array および sizeof() のテスト」)。 これには 2 つの利点があります。テストが記述しやすくなること、 そして何か問題があったときにのみそれを出力させることができるということです。
例1.4 アサーション関数を使用した Array および sizeof() のテスト
<?php
$fixture = array();
assertTrue(sizeof($fixture) == 0);
$fixture[] = 'element';
assertTrue(sizeof($fixture) == 1);
function assertTrue($condition)
{
if (!$condition) {
throw new Exception('Assertion failed.');
}
}
?>
これで、テストは完全に自動化されました。最初のバージョンでは単に テストする だけでしたが、このバージョンでは 自動テスト になっています。
自動テストを行う目的は、間違いを少なくすることです。 いくらすばらしいテストを行ったところで あなたのコードが完璧なものになるわけではありませんが、 自動テストを始めることで不具合の量を劇的に減らすことになるでしょう。 自動テストによってあなたのコードは信頼性の高いものとなり、大胆な設計変更 (リファクタリング) を行ったりチームメイトとの関係をよりよくしたり (複数チームでのテスト)、 その日の朝に比べて帰宅前のコードがよりよくなっていることを確信できたりといった効果があります。