LoginSignup
0
0

More than 5 years have passed since last update.

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

Posted at

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

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

Flameクラスの組み込み

Flameがスペアの判定をするようにする

テスト

FlameTest.php
    /**
     * @test
     */
    public function _2投目で10ピン倒した場合はスペア()
    {
        $this->Flame->recordShot(5);
        $this->assertFalse($this->Flame->isSpare()); //1投目5ピンなのでスペアでない
        $this->Flame->recordShot(5);
        $this->assertTrue($this->Flame->isSpare()); //2投目合計10ピンなのでスペア
    }

テスト実行

1) FlameTest::_2投目で10ピン倒した場合はスペア
Error: Call to undefined method App\Flame::isSpare()

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

ERRORS!
Tests: 16, Assertions: 25, Errors: 1.

ロジック修正

Flame.php
    /**
     * @return bool
     */
    public function isSpare(): bool
    {
        if ($this->score === 10 && $this->shotCount > 1) {
            return true;
        }

        return false;
    }

テスト実行

OK (16 tests, 27 assertions)

ストライクの判定ができるようにする

テスト

FlameTest.php
    /**
     * @test
     */
    public function _1投目で10ピン倒した場合はストライク()
    {
        $this->Flame->isStrike(); //投球前はストライクではない
        $this->Flame->recordShot(10);
        $this->assertTrue($this->Flame->isStrike()); //1投目で10ピン倒したのでストライク
    }

テスト実行

1) FlameTest::_1投目で10ピン倒した場合はストライク
Error: Call to undefined method App\Flame::isStrike()

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

ERRORS!
Tests: 17, Assertions: 27, Errors: 1.

ロジック修正

Flame.php
    /**
     * @return bool
     */
    public function isStrike(): bool
    {
        if ($this->score === 10 && $this->shotCount === 1) {
            return true;
        }

        return false;
    }

テスト実行

OK (17 tests, 28 assertions)

BowlingGame側のスペア判定をFlameに行わせる

ロジック修正

BowlingGame.php
    /**
     * 2投目のときにスペアかどうか判定
     * 10点とったらフラグを立てる
     *
     * @param  int     $pin [description]
     * @return void      [description]
     */
    private function isSpare(int $pin)
    {
        if ($this->shotNo === 2 && $pin + $this->lastPin === 10) {
            $this->isSpare = true;
        }
    }

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

テスト実行

OK (11 tests, 20 assertions)

BowlingGame側のストライク判定をFlameに行わせる

ロジック修正

BowlingGame.php
    /**
     * ストライク時にボーナス管理の変数をセット
     * @param  int     $pin [description]
     * @return void      [description]
     */
    private function isStrike(int $pin)
    {
        if ($pin === 10) {

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

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

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

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

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

テスト実行

OK (17 tests, 28 assertions)

BowlingGameから不要となったプロパティ$shotNo, $lastPinを削除

リファクタリング後

BowlingGame.php
<?php

namespace App;

use App¥Flame;

class BowlingGame
{
    /** @var int **/
    private $score;

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

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

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

    /** @var array */
    private $Flames;

    public function __construct()
    {
        $this->score = 0;
        $this->isSpare = false;
        $this->strikeBonusCount = 0;
        $this->doubleBonusCount = 0;
        $this->Flames[] = new Flame(); // まずはフレーム一つだけでインスタンス作成
    }

    /**
     * ボーリングの1投球の計算を実行させる
     *
     * @param int    $pin [description]
     * @return void
     */
    public function recordShot(int $pin)
    {
        //配列の一番最後が現在のフレーム
        $this->Flames[count($this->Flames)-1]->recordShot($pin);

        $this->score += $pin;

        $this->calculateSpare($pin);

        $this->calculateStrikeBonus($pin);

        $this->calculateDoubleBonus($pin);

        $this->setBonusParam();

        //フレームが完了したら新しいフレームを配列に追加
        if ($this->Flames[count($this->Flames)-1]->isFinished()) {
            $this->Flames[] = new Flame();
        }
    }

    /**
     * スペアの場合、もう一度ピンの数を足して
     * フラグを下げる
     * @param int $pin
     * @return void [description]
     */
    private function calculateSpare(int $pin)
    {
        if ($this->isSpare) {
            $this->score += $pin;
            $this->isSpare = false;
        }
    }

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

    /**
     * ダブル時の得点計算
     * @param  int    $pin [description]
     * @return void      [description]
     */
    private function calculateDoubleBonus(int $pin)
    {
        if ($this->doubleBonusCount > 0) {
            $this->score += $pin;
            --$this->doubleBonusCount;
        }
    }

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

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

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

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

    /**
     * 今回の投球がボーナス回として次の投球に影響するか判定
     * @return void
     */
    private function setBonusParam()
    {
        $this->isSpare();
        $this->isStrike();
    }

    /**
     * @return int [description]
     */
    public function calculateScore(): int
    {
        return $this->score;
    }

    /**
     * @param int
     * @return int
     */
    public function flameScore(int $flameNo): int
    {
        return $this->Flames[$flameNo]->getScore($flameNo);
    }

}

プロパティが減って、1クラスで管理するものの範囲が狭まった。
また、isSpare()など、各所で\$pinを引数として取っていた
関数に$pinが不必要になった。

0
0
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
0
0