第一章6 『Labelモデルに関わるサービスとリポジトリの実装』
2022/03/18 Laravel
前回のあらすじ
リポジトリクラスとサービスクラスをいい感じに作ってくれるテンプレートとコマンドを設定してTodoモデルとLabelモデル用のリポジトリクラスとサービスクラスを作ってTodoモデル用のリポジトリクラスとサービスクラスの中身を修正してテストした。
今回はLabelモデル用のリポジトリクラスとサービスクラスのコードを書いていく。やる事は前回とほぼ同じ。
app/Repositories/LabelRepository.phpを以下のように編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
<?php declare(strict_types=1); namespace App\Repositories; use App\Models\Label; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\ModelNotFoundException; class LabelRepository { public function all(): ?Collection { $labels = Label::all(); if ($labels->count() === 0) { return null; } return $labels; } public function create(string $title): Label { $label = new Label(); $label->title = $title; $label->save(); return $label; } public function update(int $id, string $title): Label { $label = $this->findById($id); $label->title = $title; $label->save(); return $label; } public function delete(int $id): bool { $label = $this->findById($id); return $label->delete(); } public function findById(int $id): ?Label { $label = Label::find($id); if ($label === null) { throw new ModelNotFoundException(); } return $label; } } |
次はサービスクラス。
app/Services/Label/CreateLabelService.phpを以下のように編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php declare(strict_types=1); namespace App\Services\Label; use App\Models\Label; use App\Repositories\LabelRepository; class CreateLabelService { private LabelRepository $labelRepository; /** * CreateLabelService constructor. * @param LabelRepository $labelRepository */ public function __construct(LabelRepository $labelRepository) { $this->labelRepository = $labelRepository; } /** * @param string $title * @return Label */ public function __invoke(string $title): Label { return $this->labelRepository->create($title); } } |
app/Services/Label/DeleteLabelService.phpを以下のように編集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php declare(strict_types=1); namespace App\Services\Label; use App\Repositories\LabelRepository; class DeleteLabelService { private LabelRepository $labelRepository; /** * DeleteLabelService constructor. * @param LabelRepository $labelRepository */ public function __construct(LabelRepository $labelRepository) { $this->labelRepository = $labelRepository; } /** * @param int $id * @return bool */ public function __invoke(int $id): bool { return $this->labelRepository->delete($id); } } |
app/Services/Label/GetLabelsService.phpを以下のように編集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
<?php declare(strict_types=1); namespace App\Services\Label; use App\Repositories\LabelRepository; use Illuminate\Database\Eloquent\Collection; class GetLabelsService { private LabelRepository $labelRepository; /** * GetLabelsService constructor. * @param LabelRepository $labelRepository */ public function __construct(LabelRepository $labelRepository) { $this->labelRepository = $labelRepository; } /** * @return ?Collection */ public function __invoke(): ?Collection { return $this->labelRepository->all(); } } |
app/Services/Label/UpdateLabelService.phpを以下のように編集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?php declare(strict_types=1); namespace App\Services\Label; use App\Models\Label; use App\Repositories\LabelRepository; class UpdateLabelService { private LabelRepository $labelRepository; /** * UpdateLabelsService constructor. * @param LabelRepository $labelRepository */ public function __construct(LabelRepository $labelRepository) { $this->labelRepository = $labelRepository; } /** * @param int $id * @param string $title * @return Label */ public function __invoke(int $id, string $title): Label { return $this->labelRepository->update($id, $title); } } |
リポジトリクラスとサービスクラスができたのでテストを書いていく。
テストを作成。
1 |
todo-list % sail artisan make:test Repositories/LabelRepositoryTest --unit |
tests/Unit/Repositories/LabelRepositoryTest.phpを以下のように編集。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
<?php declare(strict_types=1); namespace Tests\Unit\Repositories; use App\Repositories\LabelRepository; use Illuminate\Database\Eloquent\ModelNotFoundException; use Illuminate\Foundation\Testing\RefreshDatabase; use Tests\TestCase; class LabelRepositoryTest extends TestCase { use RefreshDatabase; public function testSuccessAllReturnedTwoLabels() { $labelRepository = new LabelRepository(); $labelRepository->create('Test1'); $labelRepository->create('Test2'); $labels = $labelRepository->all(); $this->assertCount(2, $labels); } public function testSuccessAllReturnedNull() { $labelRepository = new LabelRepository(); $labels = $labelRepository->all(); $this->assertSame(null, $labels); } public function testSuccessCreate() { $labelRepository = new LabelRepository(); $label = $labelRepository->create('Test'); $this->assertSame('Test', $label->title); } public function testSuccessUpdate() { $labelRepository = new LabelRepository(); $label = $labelRepository->create('Test'); $updatedLabel = $labelRepository->update($label->id, 'Updated'); $this->assertSame('Updated', $updatedLabel->title); } public function testFailUpdateBecauseModelNotFound() { $this->expectException(ModelNotFoundException::class); $labelRepository = new LabelRepository(); $labelRepository->update(1, 'Update'); } public function testSuccessDelete() { $labelRepository = new LabelRepository(); $label = $labelRepository->create('Test'); $this->assertDatabaseCount('labels', 1); $labelRepository->delete($label->id); $this->assertDatabaseCount('labels', 0); } public function testFailDeleteBecauseModelNotFound() { $this->expectException(ModelNotFoundException::class); $labelRepository = new LabelRepository(); $labelRepository->delete(1); } public function testSuccessFindById() { $labelRepository = new LabelRepository(); $label = $labelRepository->create('Test'); $returnedLabel = $labelRepository->findById($label->id); $this->assertSame($label->id, $returnedLabel->id); } public function testFailFindByIdBecauseModelNotFound() { $this->expectException(ModelNotFoundException::class); $labelRepository = new LabelRepository(); $labelRepository->findById(1); } } |
テストを実行。
1 |
todo-list % sail artisan test |
こんな感じのが表示されれば成功。
tests/Unit/Servicesの下にTodoモデルのサービステストを書いてしまっていたのでtests/Unit/Services/Todoの下に移動させた。
次はサービスクラスのテストを書いていく。
1 2 3 4 |
todo-list % sail artisan make:test Services/Label/CreateLabelServiceTest --unit todo-list % sail artisan make:test Services/Label/DeleteLabelServiceTest --unit todo-list % sail artisan make:test Services/Label/GetLabelsServiceTest --unit todo-list % sail artisan make:test Services/Label/UpdateLabelServiceTest --unit |
tests/Unit/Services/Label/CreateLabelServiceTest.phpを以下のように編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php declare(strict_types=1); namespace Tests\Unit\Services\Label; use App\Repositories\LabelRepository; use App\Services\Label\CreateLabelService; use Mockery\MockInterface; use Tests\TestCase; class CreateLabelServiceTest extends TestCase { public function testSuccess() { $label = 'Test'; $this->mock(LabelRepository::class, function (MockInterface $mock) use ($label) { $mock->shouldReceive('create') ->with($label) ->once(); }); $createLabelService = app(CreateLabelService::class); $createLabelService->__invoke($label); } } |
tests/Unit/Services/Label/DeleteLabelServiceTest.phpを以下のように編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
<?php declare(strict_types=1); namespace Tests\Unit\Services\Label; use App\Repositories\LabelRepository; use App\Services\Label\DeleteLabelService; use Mockery\MockInterface; use Tests\TestCase; class DeleteLabelServiceTest extends TestCase { public function testSuccess() { $id = 1; $this->mock(LabelRepository::class, function (MockInterface $mock) use ($id) { $mock->shouldReceive('delete') ->with($id) ->once(); }); $deleteLabelService = app(DeleteLabelService::class); $deleteLabelService->__invoke($id); } } |
tests/Unit/Services/Label/GetLabelsServiceTest.phpを以下のように編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
<?php declare(strict_types=1); namespace Tests\Unit\Services\Label; use App\Repositories\LabelRepository; use App\Services\Label\GetLabelsService; use Mockery\MockInterface; use Tests\TestCase; class GetLabelsServiceTest extends TestCase { public function testSuccess() { $this->mock(LabelRepository::class, function (MockInterface $mock) { $mock->shouldReceive('all') ->once(); }); $createLabelService = app(GetLabelsService::class); $createLabelService->__invoke(); } } |
tests/Unit/Services/Label/UpdateLabelServiceTest.phpを以下のように編集する。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
<?php declare(strict_types=1); namespace Tests\Unit\Services\Label; use App\Repositories\LabelRepository; use App\Services\Label\UpdateLabelService; use Mockery\MockInterface; use Tests\TestCase; class UpdateLabelServiceTest extends TestCase { public function testSuccess() { $id = 1; $label = 'Test'; $this->mock(LabelRepository::class, function (MockInterface $mock) use ($id, $label) { $mock->shouldReceive('update') ->with($id, $label) ->once(); }); $createLabelService = app(UpdateLabelService::class); $createLabelService->__invoke($id, $label); } } |
テストを実行。
1 |
todo-list % sail artisan test |
こんな感じのが表示されれば成功。