Standing on the Shoulder of Linus

Home / 2012 / 3月 / 30 / まるごとPHP vol2のテスト駆動開発を写経してみた

まるごとPHP vol2のテスト駆動開発を写経してみた

まるごとPHP vol2のテスト駆動開発を写経してみました。2008年末にインプレスジャパンから発売されたので、書店では見つけにくいかもしれません。

piece frameworkに関わっている久保敦啓さんと松藤秀治さんが書いています。私がテスト駆動開発の概要を知った記事です。3年前は読んだだけでした。今回は実際に記事にしたがってコードを書いていきました。

題材はトランプゲーム「カップル」です。書いてみる(写経する)と、読むだけでは分からなかったいろいろな発見がありました。特に、リファクタリングは参考になりました。他の人がどのようにリファクタリングするのか?の一例を知ったのは大きな収穫でした。私はペアプログラミングをしたことがないのですが、他の人がプログラミングする過程を追うことが非常に学習になるのだろうな、と思いました。

また、今更ですが phpunit の機能の豊富さを再認識しました。(lime と比較すると)環境を整えるのが多少手間がかかりますが、それを差し引いても phpunit のメリットは大きいですね。

PHPUnit 3.6.7 を使ったのですが、書籍に記載されていた assertType は deprecated になっていました。assertInstanceOfを使うようにしました。

require('couple.php');

class Games_Couple_CardDeckTest extends PHPUnit_Framework_TestCase
{
	private $_suits = array(
		Games_Couple_Suit::SPADES,
		Games_Couple_Suit::HEARTS,
		Games_Couple_Suit::DIAMONDS,
		Games_Couple_Suit::CLUBS
	);
	private $_ranks = array(1,2,3,4,5,6,7,8,9,10,11,12,13);
	public function test52cardsOnStartingUpGame()
	{
		$carddeck = new Games_Couple_CardDeck();
		$this->assertEquals(52,$carddeck->count());
	}
	public function testDrawACard()
	{
		$carddeck = new Games_Couple_CardDeck();
		$this->assertInstanceOf('Games_Couple_Card',$carddeck->draw());
	}
	public function testPutACardAfterDrawingIt()
	{
		$couple = new Games_Couple();
		$couple->draw();
		$card = $couple->viewLastCard();
		$this->assertContains($card->suit,$this->_suits);
		$this->assertContains($card->rank,$this->_ranks);
	}
	public function testPlaceCardProperlly()
	{
		$couple = new Games_Couple();
		$couple->draw();
		$this->assertInstanceOf('Games_Couple_Card',$couple->viewLastCard());
		$this->assertInstanceOf('Games_Couple_Card',$couple->view(0,0));
		$this->assertEquals($couple->viewLastCard(),$couple->view(0,0));

		$couple->draw();
		$this->assertInstanceOf('Games_Couple_Card',$couple->viewLastCard());
		$this->assertInstanceOf('Games_Couple_Card',$couple->view(0,1));
		$this->assertEquals($couple->viewLastCard(),$couple->view(0,1));

		$couple->draw();
		$this->assertInstanceOf('Games_Couple_Card',$couple->viewLastCard());
		$this->assertInstanceOf('Games_Couple_Card',$couple->view(0,2));
		$this->assertEquals($couple->viewLastCard(),$couple->view(0,2));

		$couple->draw();
		$this->assertInstanceOf('Games_Couple_Card',$couple->viewLastCard());
		$this->assertInstanceOf('Games_Couple_Card',$couple->view(0,3));
		$this->assertEquals($couple->viewLastCard(),$couple->view(0,3));

		$couple->draw();
		$this->assertInstanceOf('Games_Couple_Card',$couple->viewLastCard());
		$this->assertInstanceOf('Games_Couple_Card',$couple->view(1,0));
		$this->assertEquals($couple->viewLastCard(),$couple->view(1,0));

	}
	public function testRemoveCardsIfPairsHorizontally()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::HEARTS,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,2));
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		$card1 = $couple->draw();
		$card2 = $couple->draw();
		$card3 = $couple->draw();
		$couple->remove(0,0,0,1);
		$this->assertSame($card3,$couple->view(0,0));
		$this->assertNull($couple->view(0,1));
		$this->assertNull($couple->view(0,2));
	}
	public function testRemoveCardsIfPairsVertically()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,2));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,3));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,4));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::HEARTS,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,5));
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		$card1 = $couple->draw();
		$card2 = $couple->draw();
		$card3 = $couple->draw();
		$card4 = $couple->draw();
		$card5 = $couple->draw();
		$card6 = $couple->draw();
		$this->assertSame($card6,$couple->view(1,1));
		$couple->remove(0,0,1,0);
		$this->assertSame($card2,$couple->view(0,0));
		$this->assertSame($card6,$couple->view(0,3));
		$this->assertNull($couple->view(1,0));
		$this->assertNull($couple->view(1,1));
	}
	public function testRemoveCardsIfPairsDiagonally()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,2));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,3));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,4));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::HEARTS,2));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,5));
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		$card1 = $couple->draw();
		$card2 = $couple->draw();
		$card3 = $couple->draw();
		$card4 = $couple->draw();
		$card5 = $couple->draw();
		$card6 = $couple->draw();
		$this->assertSame($card6,$couple->view(1,1));
		$couple->remove(0,1,1,0);
		$this->assertSame($card1,$couple->view(0,0));
		$this->assertSame($card6,$couple->view(0,3));
		$this->assertNull($couple->view(1,0));
		$this->assertNull($couple->view(1,1));
	}
	/**
	 * @expectedException Games_Couple_NotSameRankException 
	 */
	public function testCannotRemoveCardsIfNotSameRank()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,2));
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		$card1 = $couple->draw();
		$card2 = $couple->draw();
		$couple->remove(0,0,0,1);
		$this->assertSame($card1,$couple->view(0,0));
		$this->assertSame($card2,$couple->view(0,1));
	}
	/**
	 * @expectedException Games_Couple_SameRankNotAdjecentException 
	 */
	public function testCannotRemoveCardsIfNotAdjacent1()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,2));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::HEARTS,1));
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		$card1 = $couple->draw();
		$card2 = $couple->draw();
		$card3 = $couple->draw();
		$couple->remove(0,0,0,2);
		$this->assertSame($card1,$couple->view(0,0));
		$this->assertSame($card2,$couple->view(0,1));
		$this->assertSame($card3,$couple->view(0,2));
	}
	/**
	 * @expectedException Games_Couple_SameRankNotAdjecentException 
	 */
	public function testCannotRemoveCardsIfNotAdjacent2()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,1));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,2));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,3));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,4));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,5));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,6));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,7));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,8));
		$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::HEARTS,1));
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		for ($i=1;$i<=9;$i++) 
		{
			$card{$i} = $couple->draw();
		}
		$couple->remove(0,0,2,0);
		$this->assertSame($card1,$couple->view(0,0));
		$this->assertSame($card9,$couple->view(2,0));
	}

	public function testNotDrawACardAfter52Drawn()
	{
		$couple = new Games_Couple();
		for ($i=1;$i<=52;$i++) 
		{
			$this->assertNotNull($couple->draw());
		}
		$this->assertNull($couple->draw());
	}
	public function testGameIsOverAfter52Drawn()
	{
		$carddeck = new Games_Couple_CardDeck();
		$carddeck->reset();
		for($rank=1;$rank<=13;$rank++)
		{
			$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::SPADES,$rank));
			$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::HEARTS,$rank));
			$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::DIAMONDS,$rank));
			$carddeck->add(new Games_Couple_Card(Games_Couple_Suit::CLUBS,$rank));
		}
		$couple = new Games_Couple();
		$couple->setCardDeck($carddeck);
		for ($i=1;$i<=52;$i++) 
		{
			$couple->draw();
		}
		for ($i=1;$i<=26;$i++) 
		{
			$this->assertfalse($couple->isGameOver());
			$couple->remove(0,0,0,1);
		}
		$this->assertTrue($couple->isGameOver());
	}
}

関連

Posted in php | Tagged ユニットテスト, リファクタリング
← 電子書籍の衝撃 WordPress 投稿毎CSS設定をadd_theme_supportで →

アーカイブ

人気の投稿とページ

  • キンドル本を印刷する(PDFに変換する)方法
  • 名古屋駅から国際センターまでの道のり(徒歩)
  • AGPL ライセンス(GPLとは似ているが違いもある)
  • 6年使ったイーモバイル(Y!mobile)を解約手続。店頭でSIM返却
  • JP-Secure SiteGuard WP Pluginは不正ログイン防止に役立つか

プロフィール

水野史土:月70万PVホームページ制作会社のレスキューワーク株式会社で、PHPソフトウェアのサポートを行っている。concrete5コミュニティリーダー、Novius OSコアコード貢献者でもある。 詳しくは管理者詳細参照。
大好評WordPress書籍「WordPressユーザーのためのPHP入門 はじめから、ていねいに。」サポートページ

Copyright © 2015 Standing on the Shoulder of Linus.