ショッピングカートクラスを作ってみる
これから、
- 前提条件:商品コード、
数量共に自然数とする
- 初期状態では、
カートに入れられた商品数は0 - 商品を追加する場合、
商品コードと数量 (正数) を指定する - 数量を変更する場合、
商品コードと変更する数量 (整数) を指定する - 商品コードを指定して、
カートに入っている数量を取得できる - すべての商品コードと数量をまとめて取得できる
- クリアすると、
カートは初期状態になる
1番目の仕様「初期状態では、カートに入れられた商品数は0」
それでは早速、
初期状態では、カートに入れられた商品数は0
を実装していきましょう。まずは、
<?php
require_once 'PHPUnit/Framework.php';
class CartTest extends PHPUnit_Framework_TestCase
{
}
それではphpunitコマンドを実行してみます。
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. F Time: 0 seconds There was 1 failure: 1) Warning(PHPUnit_Framework_Warning) No tests found in class "CartTest". FAILURES! Tests: 1, Failures: 1. $
実行するテストがまだ存在しないため、
すべての商品コードと数量をまとめて取得できる
と併せてテストを書いていくことにします。また、
<?php
require_once 'PHPUnit/Framework.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testInitCart() {
$cart = new Cart();
$this->assertTrue(is_array($cart->getItems()));
$this->assertEquals(0, count($cart->getItems()));
}
}
そして、
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. PHP Fatal error: Class 'Cart' not found in /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php on line 7 Fatal error: Class 'Cart' not found in /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php on line 7 $
今度はCartクラスが存在しないためのFatal errorとなりました。必要最低限のCartクラスとメソッドの枠だけ作成し
<?php
class Cart
{
public function getItems() {
}
}
<?php
require_once 'PHPUnit/Framework.php';
require_once 'Cart.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testInitCart() {
$cart = new Cart();
$this->assertTrue(is_array($cart->getItems()));
$this->assertEquals(0, count($cart->getItems()));
}
}
そしてphpunitコマンドの実行です。
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. F Time: 0 seconds There was 1 failure: 1) testInitCart(CartTest) Failed asserting that <boolean:false> is true. /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php:9 FAILURES! Tests: 1, Failures: 1.
$this->assertTrueメソッドでfalseが返ってきているためのエラーのようです。まだCartクラスのgetItemsメソッドを実装していたいためなので当然ですね。では、
<?php
class Cart
{
public function getItems() {
return array();
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. . Time: 0 seconds OK (1 test) $
「えっ?」
2番目の仕様「商品を追加する場合、商品コードと数量(正数)を指定する」
次に、
商品を追加する場合、商品コードと数量(正数)を指定する
です。この仕様に対するテストはどのようなものでしょうか?
- 追加するためのメソッドにコードと正数を渡すとtrueを返す
- 追加するためのメソッドにコードと非正数
(0と負の正数) を渡すと、 例外を投げる
なお、
<?php
require_once 'PHPUnit/Framework.php';
require_once 'Cart.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testInitCart() {
$cart = new Cart();
$this->assertTrue(is_array($cart->getItems()));
$this->assertEquals(0, count($cart->getItems()));
}
public function testAddPositive() {
$cart = new Cart();
$this->assertTrue($cart->add('001', 1));
}
public function testAddZero() {
$cart = new Cart();
try {
$cart->add('001', 0);
} catch (OutOfBoundsException $e) {
return;
}
$this->fail();
}
public function testAddNegative() {
$cart = new Cart();
try {
$cart->add('001', -1);
} catch (OutOfBoundsException $e) {
return;
}
$this->fail();
}
}
ここで例外のテストについて若干説明します。PHPUnit3では例外をテストする方法として次の2つが用意されています。
- PHPUnit_
Extensions_ ExceptionTestCaseを使用する - try/
catch構文とfailメソッドを使用する
先のテストケースでは、
それでは、
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .PHP Fatal error: Call to undefined method Cart::add() in /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php on line 15 Fatal error: Call to undefined method Cart::add() in /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php on line 15 $
Fatal errorが発生しましたので、
<?php
class Cart
{
public function getItems() {
return array();
}
public function add($item_cd, $amount) {
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .FFF Time: 0 seconds There were 3 failures: 1) testAddPositive(CartTest) Failed asserting that <null> is true. /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php:15 2) testAddZero(CartTest) /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php:25 3) testAddNegative(CartTest) /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php:35 FAILURES! Tests: 4, Failures: 3. $
新しいテストが正しく失敗する
<?php
class Cart
{
public function getItems() {
return array();
}
public function add($item_cd, $amount) {
if ((int)$amount > 0) {
return true;
} else {
throw new OutOfBoundsException('Invalid amount');
}
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .... Time: 0 seconds OK (4 tests) $
うまくいきました。しかし、
<?php
require_once 'PHPUnit/Framework.php';
require_once 'Cart.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testInitCart() {
$cart = new Cart();
$this->assertTrue(is_array($cart->getItems()));
$this->assertEquals(0, count($cart->getItems()));
}
public function testAddPositive() {
$cart = new Cart();
$this->assertTrue($cart->add('001', 1));
}
public function testAddZero() {
$cart = new Cart();
try {
$cart->add('001', 0);
} catch (OutOfBoundsException $e) {
return;
}
$this->fail();
}
public function testAddNegative() {
$cart = new Cart();
try {
$cart->add('001', -1);
} catch (OutOfBoundsException $e) {
return;
}
$this->fail();
}
public function testAddNotNumeric() {
$cart = new Cart();
try {
$cart->add('001', 'string');
} catch (OutOfBoundsException $e) {
return;
}
$this->fail();
}
public function testAddFloat() {
$cart = new Cart();
try {
$cart->add('001', 1.5);
} catch (OutOfBoundsException $e) {
return;
}
$this->fail();
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .....F Time: 0 seconds There was 1 failure: 1) testAddFloat(CartTest) /home/shimooka/public_html/gihyo.jp/01.phpunit/CartTest.php:55 FAILURES! Tests: 6, Failures: 1. $
小数のテストで失敗しました。addメソッドを修正し、
<?php
class Cart
{
public function getItems() {
return array();
}
public function add($item_cd, $amount) {
if (preg_match('/^\d+$/', $amount) && (int)$amount > 0) {
return true;
} else {
throw new OutOfBoundsException('Invalid amount');
}
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. ...... Time: 0 seconds OK (6 tests) $
今度は大丈夫そうですね。これで2番目の仕様の実装完了としましょう。
3番目の仕様「数量を変更する場合、商品コードと変更する数量(整数)を指定する」
続いて、
数量を変更する場合、商品コードと変更する数量(整数)を指定する
です。よく考えてみると、
- 変更するためのメソッドにコードと任意の整数を渡すと、
trueを返す - 変更するためのメソッドにコードと非数を渡すと、
例外UnexpectedValueException((OutOfBoundsExceptionと同様、 SPLで定義されている例外))を投げる
これがaddメソッドの新しい仕様となります。まずは、
<?php
require_once 'PHPUnit/Framework.php';
require_once 'Cart.php';
class CartTest extends PHPUnit_Framework_TestCase
{
public function testInitCart() {
$cart = new Cart();
$this->assertTrue(is_array($cart->getItems()));
$this->assertEquals(0, count($cart->getItems()));
}
public function testAdd() {
$cart = new Cart();
$this->assertTrue($cart->add('001', 1));
$this->assertTrue($cart->add('001', 0));
$this->assertTrue($cart->add('001', -1));
}
public function testAddNotNumeric() {
$cart = new Cart();
try {
$cart->add('001', 'string');
} catch (UnexpectedValueException $e) {
return;
}
$this->fail();
}
public function testAddFloat() {
$cart = new Cart();
try {
$cart->add('001', 1.5);
} catch (UnexpectedValueException $e) {
return;
}
$this->fail();
}
}
随分スッキリしてしまいました。それでは、
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .EEE Time: 0 seconds There were 3 errors: 1) testAdd(CartTest) OutOfBoundsException: Invalid amount /home/shimooka/public_html/gihyo.jp/CartTest.php:16 2) testAddNotNumeric(CartTest) OutOfBoundsException: Invalid amount /home/shimooka/public_html/gihyo.jp/CartTest.php:23 3) testAddFloat(CartTest) OutOfBoundsException: Invalid amount /home/shimooka/public_html/gihyo.jp/CartTest.php:33 FAILURES! Tests: 4, Errors: 3. $
3箇所でエラーが発生するようになりました。16行目は、
<?php
class Cart
{
public function getItems() {
return array();
}
public function add($item_cd, $amount) {
if (preg_match('/^\d+$/', $amount) && (int)$amount >= 0) {
return true;
} else {
throw new UnexpectedValueException('Invalid amount');
}
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .E.. Time: 0 seconds There was 1 error: 1) testAdd(CartTest) UnexpectedValueException: Invalid amount /home/shimooka/public_html/gihyo.jp/CartTest.php:17 FAILURES! Tests: 4, Errors: 1. $
今度はCartTest.
<?php
class Cart
{
public function getItems() {
return array();
}
public function add($item_cd, $amount) {
if (preg_match('/^-?\d+$/', $amount)) {
return true;
} else {
throw new UnexpectedValueException('Invalid amount');
}
}
}
$ phpunit CartTest PHPUnit 3.1.7 by Sebastian Bergmann. .... Time: 0 seconds OK (4 tests) $
テストに通りました。こちらも随分コードがスッキリしましたね。これで3番目の仕様の実装も完了としましょう。
次回は、