Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
リバーシを作って学ぶテスト駆動開発
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Akinori Takigawa
May 10, 2024
240
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
リバーシを作って学ぶテスト駆動開発
Akinori Takigawa
May 10, 2024
More Decks by Akinori Takigawa
See All by Akinori Takigawa
Nginxになりきって、FCGIでPHPと喋ろう
akinoriakatsuka
0
86
PHPUnitのテストイベントを使ってテストにかかる時間の計測をしよう
akinoriakatsuka
0
150
パイプ演算子の実装を 覗いてみよう
akinoriakatsuka
0
230
PHPでCQRS+ES入門
akinoriakatsuka
0
230
手軽に作れる電卓を作って イベントソーシングに親しもう CQRS+ESカンファレンス2026
akinoriakatsuka
0
910
Rubyで作る物理エンジン - 叡電LT
akinoriakatsuka
0
43
パイプ演算子の実装を覗いてみよう - 【非公式】PHPカンファレンス福岡2025・前日Meetup
akinoriakatsuka
0
50
技術的負債の会計学 - PHPカンファレンス広島2025
akinoriakatsuka
8
1.6k
スクラムをちゃんとやる勇気
akinoriakatsuka
0
71
Featured
See All Featured
Between Models and Reality
mayunak
4
340
Writing Fast Ruby
sferik
630
63k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
210
How to Ace a Technical Interview
jacobian
281
24k
How to make the Groovebox
asonas
2
2.2k
Claude Code のすすめ
schroneko
67
230k
Ethics towards AI in product and experience design
skipperchong
2
310
For a Future-Friendly Web
brad_frost
183
10k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
750
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
エンジニアに許された特別な時間の終わり
watany
107
250k
Why Our Code Smells
bkeepers
PRO
340
58k
Transcript
リバーシを作って学ぶ テスト駆動開発 あかつか PHP カンファレンス香川 2024 前日祭 5/10
自己紹介 あかつか / @aki_artisan 神戸でPHP を書いています レガシーシステムのLaravel への移行プロジェクト中
つくったもの
つくったもの コマンドライン上で動くリバーシ CPU と対戦できる とはいえCPU はランダムに手を打つだけで弱い CPU 対CPU 、人対人も可能 PHP8.2.7
で動作確認 https://github.com/akinoriakatsuka/reversi-php2 デモします
つくったもの(デモが動かなかった時用) 0:00
モチベーション 『テスト駆動開発』という本を写経 した 自分でも何か作ってみようと思った
テスト駆動開発とは
テスト駆動開発とは テストを先に書いてから実装を行う開発方法 今から何を作るかが明確になるので、開発がスムーズに進む リグレッションからの保護があるので、コード変更を比較的気軽にでき る レッド - グリーン - リファクタリング
レッド:失敗するテストを書く グリーン:テストを通るように(愚直に)実装する リファクタリング:テストが通る状態のままでコードを整理する(重複 を排除するなど)
テスト駆動開発の例
テスト駆動開発の例 石を置く処理をテスト駆動開発で作ってみます 指定した位置に石を置く 挟んだ石をひっくり返す ( 石を置けるかどうかを判別する)
テスト駆動開発の例 初期状態のコード抜粋 <?php namespace App\Game; class Game { private Board
$board; // 盤面 private Color $turn; // 手番 黒か白か /** * 石を置く処理 * @param int $x x 座標 * @param int $y y 座標 */ public function process(int $x, int $y): void { // ここに処理を書く } }
テスト駆動開発の例
テスト final class GameTest extends TestCase { public function testProcess():
void { $board = new Board(1, 8); $board->setStone(0, 0, new Stone(Color::BLACK)); $board->setStone(0, 1, new Stone(Color::WHITE)); $game = new Game($board); $game->process(0, 2); $this->assertSame($board->cell_list[0][1]?->getColor(), Color::BLACK); } }
テスト結果(レッド) 1) Tests\GameTest::testProcess Failed asserting that two variables reference the
same object. --- Expected +++ Actual @@ @@ -App\Game\Color Enum #473 (WHITE) +App\Game\Color Enum #211 (BLACK)
仮実装 置かれた場所と、ひっくり返す場所を決め打ちでとりあえず実装 public function process(int $x, int $y): void {
$stone = new Stone($this->turn); $this->board->setStone($x, $y, $stone); if($x === 0 && $y === 2) { $this->board->cell_list[0][1]->flip(); } $this->toggleTurn(); }
テスト結果(グリーン)🎉 .... 4 / 4 (100%) Time: 00:00.024, Memory: 8.00
MB OK (4 tests, 4 assertions)
これでいいのか? その感覚は全く正しいです 少し辛抱して先に進みましょう
テスト駆動開発の例
テスト final class GameTest extends TestCase { public function testProcess2():
void { $board = new Board(1, 8); $board->setStone(0, 0, new Stone(Color::BLACK)); $board->setStone(0, 1, new Stone(Color::WHITE)); $board->setStone(0, 2, new Stone(Color::WHITE)); $game = new Game($board); $game->process(0, 3); $this->assertSame($board->cell_list[0][1]?->getColor(), Color::BLACK); $this->assertSame($board->cell_list[0][2]?->getColor(), Color::BLACK); } }
テスト結果(レッド) 1) Tests\GameTest::testProcess2 Failed asserting that two variables reference the
same object. --- Expected +++ Actual @@ @@ -App\Game\Color Enum #484 (WHITE) +App\Game\Color Enum #204 (BLACK) /Users/akinori/development/reversi-php2/tests/GameTest.php:66 FAILURES! Tests: 5, Assertions: 5, Failures: 1.
仮実装 置かれた場所と、ひっくり返す場所を決め打ちでとりあえず実装 public function process(int $x, int $y): void {
$stone = new Stone($this->turn); $this->board->setStone($x, $y, $stone); if($x === 0 && $y === 2) { $this->board->cell_list[0][1]->flip(); } if($x === 0 && $y === 3) { $this->board->cell_list[0][1]->flip(); $this->board->cell_list[0][2]->flip(); } $this->toggleTurn(); }
テスト結果(グリーン)🎉 ..... 5 / 5 (100%) Time: 00:00.024, Memory: 8.00
MB OK (5 tests, 6 assertions)
リファクタリング コードに重複がある そもそも特定条件下でしか動かない →一般化する とりあえず一方向でやってみる
石をひっくり返す時のルール 1 マスずつ進んでいく 相手の石がある時は進む 自分の石に当たったら止まる 盤の外に出たら止まる 石のないマスに当たったら止まる 自分の石で止まった場合は、途中の相手の石をひっくり返す
リファクタリング リファクタリングではこれまでに書いたテストが依然として通ることを確認し ながら進める while (true) { $y -= 1; if
($y <= 0) { break; } $cell = $this->board->cell_list[$x][$y]; if ($cell === null) { break; } if ($cell->getColor() === $this->turn) { break; } $cell->flip(); }
テスト結果(グリーン)🎉 ..... 5 / 5 (100%) Time: 00:00.014, Memory: 8.00
MB OK (5 tests, 6 assertions)
続きは… その後もテストケースを追加して、実装を進めていく red - green - red - green -
refactoring みたいなペース
作って得られた学び
作って得られた学び 手動テストが大変な場合に特に効果を発揮する リバーシは手動で色々なパターンをテストするのが大変 リグレッションに対する保護があると自信を持って開発が進められる
作って得られた学び テストがかけるくらい疎結合になっていると、仕様追加も楽 CPU との対戦を追加するのは簡単だった
作って得られた学び テストしづらい時はスーパーセットになるような機能を作っておき、 それを使ってテストすると楽 例えば8x8 の盤面だけでは、デカくてテストしづらいので、小さい盤面も 作れるようにした とはいえ、実装がテストに影響を受けている感は否めない 皆さんの意見や経験を聞きたい!
おすすめ書籍
『テスト駆動開発』 Java で書いてあるので、PHP で書く 場合は少し違うところがある Java でまずは写経してみるのがおす すめ とにかく、写経してくれ!
『単体テストの考え方/ 使 い方』 単体テストに関する体系的な知識が 得られる テストだけでなく、設計にも役立つ コマンドクエリ分離について学べ たのが特に良かった
『ちょうぜつソフトウェ ア設計入門』 PHP でテスト駆動開発を勉強できま す PHPUnit のインストールから autoload の設定まであり、 初心者に優しい
今回のゲストスピーカー 田中ひさてるさんの著書です!
みなさんもMy リバーシつくって遊びましょう
ご清聴ありがとうございました