これからはじめる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が不必要になった。