LoginSignup
1
1

More than 5 years have passed since last update.

[ PHPUnit ] ボーリングから考えるテスト駆動開発 11テスト目

Posted at

これからはじめるTDD テスト駆動開発入門 ThinkIT Books より

ボーリングの点数計算プログラムを作る

Flameクラスの組み込み

Bonusの管理をFlameに移植し、テストが通るようにする

BowlingGameで管理しているボーナス変数

    /** @var bool **/
    private $isSpare;

    /** @var int **/
    private $strikeBonusCount;

    /** @var int **/
    private $doubleBonusCount;

Flameクラスを拡張する

  • ボーナス点を記録するためのaddBonus()を追加
  • ボーナスを受け取る回数を管理するneedBonus()を追加

テスト

Flame.php
    /**
     * @test
     */
    public function _スペア時のボーナス点加算()
    {
        $this->Flame->recordShot(5);
        $this->Flame->recordShot(5);
        $this->Flame->addBonus(5);
        $this->assertEquals(15, $this->Flame->getScore());
    }

テスト実行

1) FlameTest::_スペア時のボーナス点加算
Error: Call to undefined method App\Flame::addBonus()

/var/www/html/test/testDrivenBowling/tests/FlameTest.php:90

ERRORS!
Tests: 18, Assertions: 28, Errors: 1.

ロジック修正

Flame.php
    /** @var  int */
    private $bonus=0;

    /**
     * @param int $pin
     */
    public function addBonus(int $pin)
    {
        $this->bonus += $pin;
    }

    /**
     * @return int
     */
    public function getScore()
    {
        return $this->score + $this->bonus;
    }

テスト実行

OK (18 tests, 29 assertions)

BowlingGameに組み込む

BowlingGameが管理しているフレームにボーナスを足すときには
ボーナス対象のフレームを知っていなければならないことに注意

あくまで、ボーナス点はボーナスを出したフレームではなく
次のフレームの点数によって決まるから

テスト

BowlingGameTest.php
    /**
     * スペア時の計算
     *
     * 1投目: 3
     * 2投目: 7  //スペア
     * 3投目: 4
     *
     * 4投目以降、ガター
     *
     *
     */
    public function testSpareCase()
    {
        $this->BowlingGame->recordShot(3);
        $this->BowlingGame->recordShot(7);
        /** ↑ スペア **/

        $this->BowlingGame->recordShot(4);
        $this->loopRecordShot(17, 0);

        $this->assertEquals(18, $this->BowlingGame->calculateScore());

        /*
         * スペアのテスト時にフレームの点数がボーナス込みで
         * 14点であることを確認
         */
        $this->assertEquals(14, $this->BowlingGame->flameScore(0));
    }

テスト実行

1) BowlingGameTest::testSpareCase
Failed asserting that 10 matches expected 14.

/var/www/html/test/testDrivenBowling/tests/BowlingGameTest.php:61

FAILURES!
Tests: 18, Assertions: 30, Failures: 1.

ロジック修正

BowlingGame.php
    /** @var  int スペアのフレームを記録 */
    private $spareFlameNo;

    /**
     * スペアの場合、もう一度ピンの数を足して
     * フラグを下げる
     * @param int $pin
     * @return void [description]
     */
    private function calculateSpare(int $pin)
    {
        if ($this->isSpare) {
            //スペアのボーナスをフレーム側に加算
            $this->Flames[$this->spareFlameNo]->addBonus($pin);
            $this->spareFlameNo = null;

            $this->score += $pin;
            $this->isSpare = false;
        }
    }

    /**
     * 2投目のときにスペアかどうか判定
     * 10点とったらフラグを立てる
     *
     * @return void      [description]
     */
    private function isSpare()
    {
        if ($this->Flames[count($this->Flames)-1]->isSpare()) {
            $this->isSpare = true;

            //スペアをとったフレーム番号を記憶
            $this->spareFlameNo = count($this->Flames)-1;
        }
    }

テスト実行

OK (18 tests, 30 assertions)

同様にストライクの場合も組み込む

テスト

BowlingGameTest.php
    /**
     * 初球ストライクのケース
     *
     * 1投目: ストライク
     * 2投目: 3
     * 3投目: 3
     * 4投目: 1
     *
     * 残りガター
     *
     */
    public function testStrikeAtFirstFlame()
    {
        $this->BowlingGame->recordShot(10);
        $this->BowlingGame->recordShot(3);
        $this->BowlingGame->recordShot(3);
        $this->BowlingGame->recordShot(1);

        $this->loopRecordShot(15, 0);

        $this->assertEquals(23, $this->BowlingGame->calculateScore());

        //ストライク時に1フレーム目の点数が16点になっているか
        $this->assertEquals(16, $this->BowlingGame->flameScore(0));
    }

テスト実行

1) BowlingGameTest::testStrikeAtFirstFlame
Failed asserting that 10 matches expected 16.

/var/www/html/test/testDrivenBowling/tests/BowlingGameTest.php:116

FAILURES!
Tests: 18, Assertions: 31, Failures: 1.

ロジック修正

BowlingGame.php
    /** @var  int スペアのフレームを記録 */
    private $strikeFlameNo;

    /**
     * ストライク時の得点計算
     * @param  int    $pin [description]
     * @return void      [description]
     */
    private function calculateStrikeBonus(int $pin)
    {
        if ($this->strikeBonusCount > 0) {
            $this->Flames[$this->strikeFlameNo]->addBonus($pin);
            $this->score += $pin;
            --$this->strikeBonusCount;
        }
    }

    /**
     * ストライク時にボーナス管理の変数をセット
     * @return void      [description]
     */
    private function isStrike()
    {
        if ($this->Flames[count($this->Flames)-1]->isStrike()) {

            $this->strikeFlameNo = count($this->Flames)-1;

            if ($this->strikeBonusCount !== 0) {
                $this->doubleBonusCount = 2;
            }

            if ($this->strikeBonusCount === 0) {
                $this->strikeBonusCount = 2;
            }
        }
    }


テスト実行

OK (18 tests, 31 assertions)

一旦終わり、次回はダブルストライクとターキーを検討

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1