第3章 タスクの更新と完了
02.データを扱う
タスクデータの更新
今回は今までと違い、「Formから受け取ったデータ」を使って、「データベースの更新」が必要となる。 テストとはいえ、データベースへの追加や更新を行なうと、その結果はデータベース内に残ってしまう。
そこで、データベースへの追加や更新を行なうテストの場合に、方針を決める必要がある。
- テスト用のデータベースを用意する。かつ、データベースの内容に対して、テストは依存しない。
- テスト実行の度に、データベース内のデータを消す。(必然的に、データベースの内容に対して、テストは依存しない。)
- テスト実行の度に、テストで追加・変更した結果のみをロールバックする。(データベースの内容に対して、テストは依存しても構わない。)
2.か3.の方針を取る場合、それぞれテストにおいてtrait
による機能追加で実現可能だ。
2.はRefreshDatabase
やDatabaseMigrations
、3.はDatabaseTransactions
を使えば良い。
基本的に2.が理想的ではあるが、「手動操作」で追加・更新したデータがテスト実施によって消えてしまう。
一方、3.であれば実施したテストで扱ったものだけを消してくれるので、 「手動操作」で追加・更新したデータを残すことが可能だ。
今回は、「手動操作」に該当するのがseeder
で追加したデータだ。
seeder
で追加したデータに対するテストを第1章で書いており、
かつ、テストがデータに依存した状態だ。
一旦3.の方針で進み、この章の最後で2.の方針で整理するようにしてみよう。
タスクデータの更新テスト
さっそく、テストを書いてみよう。
tests/Unit/TaskTest.php
にテストメソッドを追加してみる。
<?php
namespace Tests\Unit;
use App\Task;
use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\RefreshDatabase;
class TaskTest extends TestCase
{
use DatabaseTransactions;
/**
* Get Seeder Tasks Test
*
* @return void
*/
public function testGetSeederTasks()
{
// 全件取得
$tasks = Task::all();
// 3件取得できるはず
$this->assertEquals(3, count($tasks));
// 実行完了していないものを取得
$taskNotFinished = Task::where('executed', false)->get();
// 2件取得できるはず
$this->assertEquals(2, count($taskNotFinished));
// 実行完了しているものを取得
$taskFinished = Task::where('executed', true)->get();
// 1件取得できるはず
$this->assertEquals(1, count($taskFinished));
// 「テストタスク」というタイトルのレコードを取得
$task1 = Task::where('title', "テストタスク")->first();
// 実行完了していないはず
$this->assertFalse(boolval($task1->executed));
// 「終了タスク」というタイトルのレコードを取得
$task1 = Task::where('title', "終了タスク")->first();
// 実行完了しているはず
$this->assertTrue(boolval($task1->executed));
}
public function testGetTaskDetail()
{
$tasks = Task::find(2);
$this->assertEquals('テストタスク', $tasks->title);
}
public function testGetTaskDetailNotExists()
{
$tasks = Task::find(0);
$this->assertNull($tasks);
}
public function testUpdateTask()
{
$task = Task::create([
'title' => 'test',
'executed' => false,
]);
$this->assertEquals('test', $task->title);
$this->assertFalse($task->executed);
$task->fill(['title' =>'テスト']);
$task->save();
$task2 = Task::find($task->id);
$this->assertEquals('テスト', $task2->title);
}
}
6行目と13行目が、DatabaseTransactions
を使うための設定だ。
60〜75行目で「タスクの追加」と「タスクの更新」を行なっている。
追加の場合にはcreate()
、
更新の場合には既存のオブジェクトにfill()
でデータを格納してsave()
、となる。
では、これを実行してみよう。
$ vendor/bin/phpunit
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
.......E 8 / 8 (100%)
Time: 829 ms, Memory: 16.00MB
There was 1 error:
1) Tests\Unit\TaskTest::testUpdateTask
Illuminate\Database\Eloquent\MassAssignmentException: title
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:232
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:152
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:290
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:1068
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:756
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1470
/Users/[ユーザ名]/task-manager/task-manager/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:1482
/Users/[ユーザ名]/task-manager/task-manager/tests/Unit/TaskTest.php:63
ERRORS!
Tests: 8, Assertions: 11, Errors: 1.
おっと、エラーが発生してしまった。
MassAssignmentException
という例外だが、Laravelのドキュメントにある通り、
モデルクラスの設定が不足している、、ということのようだ。
https://readouble.com/laravel/5.5/ja/eloquent.html#mass-assignment
単純に言えば、「追加・更新を行なっても良いカラム」か、「追加・更新を行なってはいけないカラム」を、 指定しておかなければいけないようだ。
追加・更新を行なうカラムの制限
今回必要なのは、タスクの「タイトル」と「実行済みフラグ」の二つを作成・更新できれば良いので、 この二つのカラムを「追加・更新を行なっても良いカラム」とするような書き方にする。
app/Task.php
を以下のように編集する。
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Task extends Model
{
protected $fillable = ['title', 'executed'];
}
これでタスクの「タイトル」と「実行済みフラグ」の二つを作成・更新できるようになるので、 テストが成功するはずだ。
$ vendor/bin/phpunit
PHPUnit 6.5.8 by Sebastian Bergmann and contributors.
........ 8 / 8 (100%)
Time: 790 ms, Memory: 16.00MB
OK (8 tests, 14 assertions)
無事に成功となった。
「更新」のテストのために、事前に「追加」を行なっているのは意味があるのか?と思うかもしれないが、 「テストのための事前準備」として必要なので、気にせずに行なって欲しい。
このようなことをやっても、DatabaseTransactions
によって影響はテストの中だけとなるので、
細かいことをきにする必要は無い。
また、後ほどRefreshDatabase
やDatabaseMigrations
へと切り替えた場合には、
全てのテストでこのような対応が必要となる。
次は、詳細画面で更新を行なえるように修正を行なっていこう。