ショッピングカートクラスを作ってみる
これから、実際にPHPUnitを使ってテストケースを書きつつ、クラスの実装を行ってみましょう。今回作成するのは、以下の機能を持つ簡易的なショッピングカートクラス(Cartクラス)です。
- 初期状態では、カートに入れられた商品数は0
- 商品を追加する場合、商品コードと数量(正数)を指定する
- 数量を変更する場合、商品コードと変更する数量(整数)を指定する
- 商品コードを指定して、カートに入っている数量を取得できる
- すべての商品コードと数量をまとめて取得できる
- クリアすると、カートは初期状態になる
1番目の仕様「初期状態では、カートに入れられた商品数は0」
それでは早速、1番目の仕様である
を実装していきましょう。まずは、テストケースから作成しましょう。Cartクラスのテストケースなので、テストケースのクラス名をCartTest、ファイル名をCartTest.phpとします。
それではphpunitコマンドを実行してみます。
実行するテストがまだ存在しないため、失敗してしまいます。それでは、1つ目の仕様に対するテストを書いてみます。ただし、1つ目の仕様だけでは「どうやって初期状態の商品数が0であることをテストするか?」が書きにくいと思います。そこで、5番目の仕様
と併せてテストを書いていくことにします。また、5番目の仕様で実装する予定のメソッドをgetItemsメソッドとし、getItemsメソッドは商品コードをキー、カートに入れられた商品の数を値とするハッシュを返すものとしました。
そして、再びphpunitコマンドを実行します。
今度はCartクラスが存在しないためのFatal errorとなりました。必要最低限のCartクラスとメソッドの枠だけ作成し(Cart.php)、テストケースで読み込むようにしましょう。
そしてphpunitコマンドの実行です。
$this->assertTrueメソッドでfalseが返ってきているためのエラーのようです。まだCartクラスのgetItemsメソッドを実装していたいためなので当然ですね。では、getItemsメソッドを実装しましょう。
「えっ?」と思われたかも知れませんが、まずはテストが通るようになりました。ひとまず、これで実装完了としておきましょう。
2番目の仕様「商品を追加する場合、商品コードと数量(正数)を指定する」
次に、2番目の仕様
です。この仕様に対するテストはどのようなものでしょうか?ここではまず以下の2つを考えてみます。
- 追加するためのメソッドにコードと正数を渡すとtrueを返す
- 追加するためのメソッドにコードと非正数(0と負の正数)を渡すと、例外を投げる
なお、投げられる例外は、SPL(Standard PHP Library)拡張モジュールで定義されている例外OutOfBoundsExceptionとします。それでは、テストケースにテストを追加します。
ここで例外のテストについて若干説明します。PHPUnit3では例外をテストする方法として次の2つが用意されています。
- PHPUnit_Extensions_ExceptionTestCaseを使用する
- try/catch構文とfailメソッドを使用する
先のテストケースでは、testAddZeroメソッドとtestAddNegativeメソッドで例外のテストを行っており、2番目の方法を採っています。testXXXXメソッド内で使われているfailメソッドは「ボトルネックメソッド」と呼ばれ、テストが失敗した際PHPUnitによってコールされるメソッドです。テストに失敗してtry/catch文を通過した場合に、このfailメソッドを直接呼び出すことで「テストに失敗した」ことをPHPUnitに伝えています。また、階層構造を持った例外をテストする場合、意図した例外を正しく捕捉しているかどうか、十分注意してください。なお、PHPUnit_Extensions_ExceptionTestCaseの解説については、PHPUnitポケットガイドを参照してください。
それでは、テストを実行しましょう。
Fatal errorが発生しましたので、Cartクラスにaddメソッドを実装します。
新しいテストが正しく失敗する(変な表現ですが)ことを確認しましたので、addメソッドの実装を行いましょう。
うまくいきました。しかし、これで本当に「正数」だけうまく通ると言えるでしょうか?数量に小数や文字列を渡された場合のテストも追加して確認しておきましょう。
小数のテストで失敗しました。addメソッドを修正し、数量のフォーマットをチェックすることにします。
今度は大丈夫そうですね。これで2番目の仕様の実装完了としましょう。
3番目の仕様「数量を変更する場合、商品コードと変更する数量(整数)を指定する」
続いて、3番目の仕様
です。よく考えてみると、2番目の仕様で実装した内容と今回実装しようとしている内容は「商品コードと数量を指定してカートの中身を変更する」ことに変わりありません。1つのメソッドに統一できそうですね。今回はaddメソッドを変更することで、3番目の仕様を実装する事にしましょう。それでは今までと同様、仕様に対するテストを考えてみます。
- 変更するためのメソッドにコードと任意の整数を渡すと、trueを返す
- 変更するためのメソッドにコードと非数を渡すと、例外UnexpectedValueException((OutOfBoundsExceptionと同様、SPLで定義されている例外))を投げる
これがaddメソッドの新しい仕様となります。まずは、addメソッドの実装で用意したテストを修正しましょう。
随分スッキリしてしまいました。それでは、phpunitコマンドを実行して、テスト結果を確認しておきましょう。
3箇所でエラーが発生するようになりました。16行目は、数量に0を指定できるかどうかのテストで、今回仕様変更になった箇所です。23行目と33行目は投げられる例外が変更になったことが原因です。それでは、Cartクラスを変更します。
今度はCartTest.phpの17行目にある数量に負数を指定した場合のテストで失敗しています。同様に修正します。
テストに通りました。こちらも随分コードがスッキリしましたね。これで3番目の仕様の実装も完了としましょう。
次回は、残りの3つの仕様をテストを作りながら実装していきます。