第3章 タスクの更新と完了

02.データを扱う

タスクデータの更新

今回は今までと違い、「Formから受け取ったデータ」を使って、「データベースの更新」が必要となる。 テストとはいえ、データベースへの追加や更新を行なうと、その結果はデータベース内に残ってしまう。

そこで、データベースへの追加や更新を行なうテストの場合に、方針を決める必要がある。

  1. テスト用のデータベースを用意する。かつ、データベースの内容に対して、テストは依存しない。
  2. テスト実行の度に、データベース内のデータを消す。(必然的に、データベースの内容に対して、テストは依存しない。)
  3. テスト実行の度に、テストで追加・変更した結果のみをロールバックする。(データベースの内容に対して、テストは依存しても構わない。)

2.か3.の方針を取る場合、それぞれテストにおいてtraitによる機能追加で実現可能だ。 2.はRefreshDatabaseDatabaseMigrations、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によって影響はテストの中だけとなるので、 細かいことをきにする必要は無い。 また、後ほどRefreshDatabaseDatabaseMigrationsへと切り替えた場合には、 全てのテストでこのような対応が必要となる。

次は、詳細画面で更新を行なえるように修正を行なっていこう。

Last Updated (JST): 7/7/2019, 2:32:08 PM