Slide 1

Slide 1 text

継続的にLaravelのUnitTestを書く上で 気をつけていること 2021 年 9 月 28 日 ( 火 )

Slide 2

Slide 2 text

自己紹介 hyroky.(@handm871) 専門領域: 趣味: バックエンド🍓 ユニットテスト・設計 筋トレ🦾

Slide 3

Slide 3 text

テストとPHP周りについて ● テスト駆動開発歴:5年 ● PHP歴:5年 ● Laravel歴:3年

Slide 4

Slide 4 text

テストコードについて思うこと ● サンプルコードが圧倒的に少ない ● プロダクトコードの設計は たくさん ある ○ テストコードの設計は あんまり ない

Slide 5

Slide 5 text

伝えたい人 テスト駆動開発に ● 興味がある人 ● 初心者

Slide 6

Slide 6 text

今日話すこと UnitTest について 依存注入できる形で実装する

Slide 7

Slide 7 text

サンプルコード class FetchTodoService { public function exec(string $user_id, int $todo_id): array { $todo_repos = new TodoRepository(); $result = $todo_repos->fetchTodo($todo_id, $user_id); if ($result === []) { throw new NotFoundException('Todoのデータが存在しません'); } return $result; } }

Slide 8

Slide 8 text

何がまずいのか? ● TodoRepositoryに依存している ○ メソッド内で `new` している ○ 代替できないことが問題 ○ DBにテストデータを作る必要がある

Slide 9

Slide 9 text

Feature Test ● [GET]: /api/todo ● 実データを用いて機能の振る舞いを検証

Slide 10

Slide 10 text

Unit Test ● TodoListController ○ TodoFetchService ■ TodoRepository

Slide 11

Slide 11 text

Unit Test TodoListController Jsonを返す FetchTodoService DBから受け取った値を検証する TodoRepository DBへ接続・SQLを実行

Slide 12

Slide 12 text

Unit Test TodoListController Jsonを返す FetchTodoService DBから受け取った値を検証する TodoRepository DBへ接続・SQLを実行 FetchTodoService はDB接続の責務は不要

Slide 13

Slide 13 text

変更前 class FetchTodoService { public function exec(string $user_id, int $todo_id): array { $todo_repos = new TodoRepository(); $result = $todo_repos->fetchTodo($todo_id, $user_id); if ($result === []) { throw new NotFoundException('Todoのデータが存在しません'); } return $result; } }

Slide 14

Slide 14 text

変更後 class FetchTodoService { public function exec( string $user_id, int $todo_id, TodoRepository $todo_repos, ): array { $result = $todo_repos->fetchTodo($todo_id, $user_id); if ($result === []) { throw new LogicException('Todoのデータが存在しません'); } return $result; } } TodoRepository を外部から注入

Slide 15

Slide 15 text

テストのサンプル class FetchTodoServiceTest extends TestCase { /** @test */ public function データが存在しない場合、空の配列を返すべき (): void { $user_id = 'user_id'; $todo_id = 999999; $todo_repos_mock = Mockery::mock(TodoRepository ::class); $todo_repos_mock ->shouldReceive ('fetchTodo') ->once() ->with($user_id, $todo_id) ->andReturn([]); $service = new TodoService(); parent::expectedException (LogicException ::class); parent::expectExceptionMessage ('Todoのデータが存在しません '); $service->exec($user_id, $todo_id, $todo_repos_mock ); } } 引数を設定 返り値を設定

Slide 16

Slide 16 text

何がまずいのか? ● TodoRepositoryに依存している ○ メソッド内で `new` している ○ 代替できないことが問題 ○ DBにテストデータを作る必要がある

Slide 17

Slide 17 text

テスト駆動開発から見えるもの ● テストを書くことが大変...とおもったら ○ 設計を見直すいい機会

Slide 18

Slide 18 text

おわり