PHPUnit3で始めるユニットテスト

第3回 ショッピングカートクラスを作ってみる(2)

この記事を読むのに必要な時間:およそ 18 分

6番目の仕様「クリアすると,カートは初期状態になる」

次は最後の仕様

クリアすると,カートは初期状態になる

です。仕様に対するテストはどの様になるでしょうか?とりあえず,

  • clearメソッドを呼び出すと,コンストラクタを呼び出した場合と同様の動作をする

ということで良さそうです。早速テストケースにテストを追加し,Cartクラスにclearメソッドの定義を追加しましょう。

<?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();
    }

    public function testGetAmount() {
        $cart = new Cart();
        $this->assertEquals(0, $cart->getAmount('001'));
        $cart->add('001', 1);
        $this->assertEquals(1, $cart->getAmount('001'));

        $this->assertEquals(0, $cart->getAmount('999'));

        $cart->add('002', 1);
        $this->assertEquals(1, $cart->getAmount('001'));
        $this->assertEquals(1, $cart->getAmount('002'));

        $cart->add('001', -1);
        $this->assertEquals(0, $cart->getAmount('001'));
        $this->assertEquals(1, $cart->getAmount('002'));
    }

    public function testGetItems() {
        $cart = new Cart();
        $cart->add('001', 3);
        $this->assertEquals(1, count($cart->getItems()));
        $cart->add('002', 2);
        $this->assertEquals(2, count($cart->getItems()));

        $items = $cart->getItems();
        $this->assertEquals(3, $items['001']);
        $this->assertEquals(2, $items['002']);
    }

    public function testClearCart() {
        $cart = new Cart();
        $cart->add('001', 1);
        $cart->add('002', 2);
        $cart->add('003', 3);
        $cart->clear();
        $this->assertTrue(is_array($cart->getItems()));
        $this->assertEquals(0, count($cart->getItems()));
    }
}
<?php
class Cart
{
    private $items;

    public function __construct() {
        $this->items = array();
    }

    public function getItems() {
        return $this->items;
    }

    public function add($item_cd, $amount) {
        if (preg_match('/^-?\d+$/', $amount)) {
            if (!isset($this->items[$item_cd])) {
                $this->items[$item_cd] = 0;
            }
            $this->items[$item_cd] += (int)$amount;
            return true;
        } else {
            throw new UnexpectedValueException('Invalid amount');
        }
    }

    public function getAmount($item_cd) {
        if (isset($this->items[$item_cd])) {
            return $this->items[$item_cd];
        } else {
            return 0;
        }
    }

    public function clear() {
    }
}
$ phpunit CartTest
PHPUnit 3.1.7 by Sebastian Bergmann.

......F

Time: 0 seconds

There was 1 failure:

1) testClearCart(CartTest)
Failed asserting that <integer:3> matches expected value <integer:0>.
/home/shimooka/public_html/gihyo.jp/CartTest.php:76

FAILURES!
Tests: 7, Failures: 1.
$ 

それでは,clearメソッドを実装していきます。clearメソッドの動作はコンストラクタと同様の動作をすれば良いので,コンストラクタのコード内容をそのままコピー&ペーストして実装することにします。

<?php
class Cart
{
    private $items;

    public function __construct() {
        $this->items = array();
    }

    public function getItems() {
        return $this->items;
    }

    public function add($item_cd, $amount) {
        if (preg_match('/^-?\d+$/', $amount)) {
            if (!isset($this->items[$item_cd])) {
                $this->items[$item_cd] = 0;
            }
            $this->items[$item_cd] += (int)$amount;
            return true;
        } else {
            throw new UnexpectedValueException('Invalid amount');
        }
    }

    public function getAmount($item_cd) {
        if (isset($this->items[$item_cd])) {
            return $this->items[$item_cd];
        } else {
            return 0;
        }
    }

    public function clear() {
        $this->items = array();
    }
}
$ phpunit CartTest
PHPUnit 3.1.7 by Sebastian Bergmann.

.......

Time: 0 seconds


OK (7 tests)
$ 

テストにパスしました。⁠これで実装完了」といきたいところですが,重複するコードは可能な限り避けたいものです。そこでコンストラクタのコードを変更し,clearメソッドを呼び出すことにしましょう。

<?php
class Cart
{
    private $items;

    public function __construct() {
        $this->clear();
    }

    public function getItems() {
        return $this->items;
    }

    public function add($item_cd, $amount) {
        if (preg_match('/^-?\d+$/', $amount)) {
            if (!isset($this->items[$item_cd])) {
                $this->items[$item_cd] = 0;
            }
            $this->items[$item_cd] += (int)$amount;
            return true;
        } else {
            throw new UnexpectedValueException('Invalid amount');
        }
    }

    public function getAmount($item_cd) {
        if (isset($this->items[$item_cd])) {
            return $this->items[$item_cd];
        } else {
            return 0;
        }
    }

    public function clear() {
        $this->items = array();
    }
}
$ phpunit CartTest
PHPUnit 3.1.7 by Sebastian Bergmann.

.......

Time: 0 seconds


OK (7 tests)
$ 

テスト結果も問題ないようです。

著者プロフィール

下岡秀幸(しもおかひでゆき)

PHP関連の情報サイト「Do You PHP?」の管理人。PHP歴は長いが,あまり仕事で使ったことがないという噂がある。最近はα版のPEAR・PECLに手を出しては地雷を踏んでいることが多い。

URLhttp://www.doyouphp.jp/http://d.hatena.ne.jp/shimooka/