これからはじめる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)
一旦終わり、次回はダブルストライクとターキーを検討