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

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

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

## 2連続ストライクの場合の計算ロジック。いわゆるダブル

BowlingGameTestに以下の機能を実装。

- 2連続ストライクの場合に正しく計算が動くようにする

### テストを書く

```php
    /**
     * 2球連続ストライクのケース
     *
     * 1投目: ストライク
     * 2投目: ストライク
     * 3投目: 3
     * 4投目: 1
     *
     * 残りガター
     *
     * @return void
     */
    public function testDoubleStrikeAtFirstFlame()
    {
        $this->BowlingGame->recordShot(10); //10+(10+3)
        $this->BowlingGame->recordShot(10); //10+(3+1)
        $this->BowlingGame->recordShot(3); //3
        $this->BowlingGame->recordShot(1); //1           [計41]

        $this->loopRecordShot(14, 0);

        $this->assertEquals(41, $this->BowlingGame->calculateScore());
    }


```

### 実行して怒られる

```bash
1) BowlingGameTest::testDoubleStrikeAtFirstFlame
Failed asserting that 38 matches expected 41.
```

### テストが通るように処理を書く(__最小の構成で__)

- テストが通らない原因

__二回目のストライクにて、ボーナス計算用の変数が上書きされてしまう__
($this->strikeBonusCountが 2→1→0でなくて、2→1→2となってしまっている)
そのため今回のケースでは3点少ない計算になっている

```php
    /**
     * ストライク時にボーナス管理の変数をセット
     * @param  int     $pin [description]
     * @return void      [description]
     */
    private function isStrike(int $pin)
    {
        if ($pin === 10) {
            $this->strikeBonusCount = 2; //この部分！！
        }
    }
```

- 解決策

ボーナス管理用の変数を使う
__イケてないかもしれないが、問題を最小限で解決していく方針に従う__

#### 設計

① doubleBonusCountを定義

② calculateStrike()内にて

- __doubleBonusCount > 0__の場合、\$pinを$scoreに加算
- __doubleBonusCount > 0__の場合、-1をする

③ isStrike()内にて

- __$strikeBonusCount === 0__の場合、2をセット
- __$strikeBonusCount !== 0__の場合、doubleBonusCountに2をセット

↑は順序重要なので注意。
逆にすると一回目のストライクでdoubleBonusCountがセットされてしまう

#### 実装

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

        if ($this->strikeBonusCount > 0) {
            $this->score += $pin;
            --$this->strikeBonusCount;
        }
    }

    /**
     * ストライク時にボーナス管理の変数をセット
     * @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;
            }
        }
    }
```

#### テスト実行

```bash
OK (6 tests, 6 assertions)
```

## 3連続ストライクの場合の計算ロジック。いわゆるターキー

#### テストを書く

```php
    /**
     * 3球連続ストライクのケース
     *
     * 1投目: ストライク
     * 2投目: ストライク
     * 3投目: ストライク
     * 4投目: 3
     * 5投目: 1
     *
     * 残りガター
     *
     */
    public function testTurkeyAtFirstFlame()
    {
        $this->BowlingGame->recordShot(10); //10+(10+10)
        $this->BowlingGame->recordShot(10); //10+(10+3)
        $this->BowlingGame->recordShot(10); //10+(3+1)
        $this->BowlingGame->recordShot(3); //3
        $this->BowlingGame->recordShot(1); //1           [計71]

        $this->loopRecordShot(12, 0);

        $this->assertEquals(71, $this->BowlingGame->calculateScore());
    }
```

#### テスト実行

```bash
OK (7 tests, 7 assertions)
```

## 感想

ダブルを実装した後にターキーの確認までできたのはテストを実行できるのは楽だった
フラグ管理部分が多いのでその責任はテストを頼りに別場所に移したいかな