これからはじめるTDD テスト駆動開発入門 ThinkIT Books より
ボーリングの点数計算プログラムを作る
フレーム単位でのスコアを取得する
ダブルストライクとターキーの処理を移していく
テスト
BowlingGameTest.php
/**
* 2球連続ストライクのケース
*
* 1投目: ストライク
* 2投目: ストライク
* 3投目: 3
* 4投目: 1
*
* 残りガター
*
*/
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());
//ストライク時に1フレーム目と2フレーム目の点数がただし以下
$this->assertEquals(23, $this->BowlingGame->flameScore(0));
$this->assertEquals(14, $this->BowlingGame->flameScore(1));
}
テスト実行
1) BowlingGameTest::testDoubleStrikeAtFirstFlame
Failed asserting that 20 matches expected 23.
/var/www/html/test/testDrivenBowling/tests/BowlingGameTest.php:142
FAILURES!
Tests: 18, Assertions: 32, Failures: 1.
ロジック修正
BowlingGame.php
/** @var int ダブルストライクのフレームを記録 */
private $strikeDoubleFlameNo;
/**
* ダブル時の得点計算
* @param int $pin [description]
* @return void [description]
*/
private function calculateDoubleBonus(int $pin)
{
if ($this->doubleBonusCount > 0) {
//ダブルの一投目は二つ前のフレームに送る
if ($this->doubleBonusCount === 2) {
$this->Flames[$this->strikeDoubleFlameNo-1]->addBonus($pin);
} else {
$this->Flames[$this->strikeDoubleFlameNo]->addBonus($pin);
}
$this->score += $pin;
--$this->doubleBonusCount;
}
}
/**
* ストライク時にボーナス管理の変数をセット
* @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->strikeDoubleFlameNo = count($this->Flames)-1;
$this->doubleBonusCount = 2;
}
if ($this->strikeBonusCount === 0) {
$this->strikeBonusCount = 2;
}
}
}
テスト実行
OK (18 tests, 33 assertions)
オープンフレームの概念を取り込んでおく
- ボーナス計算が発生しないフレームのこと
FlameにneedBonus()を実装し、スペアとストライク以外では
falseを返すようにする
一気にやることにします。
もうそろそろめんどくさくなってきたw
テスト
/**
* @test
*/
public function _オープンフレームにボーナスは不要()
{
$this->Flame->recordShot(3);
$this->Flame->recordShot(3);
$this->assertFalse($this->Flame->needBonus());
}
/**
* @test
*/
public function _スペアのボーナスは1投分で完了()
{
$this->Flame->recordShot(5);
$this->Flame->recordShot(5);
$this->assertTrue($this->Flame->needBonus()); //ボーナス付与前
$this->Flame->addBonus(5);
$this->assertFalse($this->Flame->needBonus());
}
/**
* @test
*/
public function _ストライクのボーナスは2投分で完了()
{
$this->Flame->recordShot(10);
$this->Flame->addBonus(5);
$this->assertTrue($this->Flame->needBonus()); //ボーナス付与後①
$this->Flame->addBonus(5);
$this->assertFalse($this->Flame->needBonus()); //ボーナス付与後②
}
これが通るロジックは↓
ロジック修正
Flame.php
/** @var int */
private $bonusCount=0;
/**
* @param int $pin
*/
public function addBonus(int $pin)
{
$this->bonus += $pin;
$this->bonusCount += 1;
}
/**
* @return bool
*/
public function needBonus(): bool
{
if ($this->isSpare()) {
return $this->bonusCount < 1;
}
if ($this->isStrike()) {
return $this->bonusCount < 2;
}
return false;
}
テスト実行
OK (21 tests, 38 assertions)
ゲームの合算値をFlameから返す($scoreプロパティの排除)
これを
BowlingGameTest.php
/**
* @return int [description]
*/
public function calculateScore(): int
{
return $this->score;
}
こう
BowlingGame.php
/**
* @return int [description]
*/
public function calculateScore(): int
{
$total = 0;
foreach ($this->Flames as $Flame) {
$total += $Flame->getScore();
}
return $total;
}
テストも通る
OK (21 tests, 38 assertions)
終了
まだ改良できる点はあるものの、もう流れはつかめたし
責務も分担できたし一旦クローズ。
気が向いたら気合の入ったリファウタリングを行ってアップしたい