Laravel 自動テストPHPUnit版

Laravel

この記事のゴール

  • LaravelでPHPUnitを使って自動テストを実行しオールグリーン(全てOK)にする。

前提条件

  • Laravel でPHPUnitが使える状態。

 ※まだの場合は、以前の記事を参考にしてください。

  • フォームから基本的なCRUD(作成/読取/更新/削除)操作ができる状態

 ※まだの場合は前回の記事を参考にしてください。

これからやる作業

  • テスト用環境設定ファイル作成
  • テスト用データベースのマイグレーション
  • テストコード作成
  • テスト実行

テスト用環境設定ファイル作成

テスト実行時には、テスト用のデータベースが用意されているので、

そちらを確実に使用するように、Laravelの環境ファイルを作成します。

プロジェクトトップフォルダにある「.env」ファイルをコピーして、

新しいファイル「.env.testing」を作成します。

次のように編集して保存します。

修正す箇所は、2行目と14行目で、「=」の後ろを「testing」に修正するだけです。

APP_NAME=Laravel
APP_ENV=testing
APP_KEY=base64:r3t3Xyd9S12D2F19ZxkoFCCFN+0IAhei/2LRIJ1U5dc=
APP_DEBUG=true
APP_URL=http://localhost

LOG_CHANNEL=stack
LOG_DEPRECATIONS_CHANNEL=null
LOG_LEVEL=debug

DB_CONNECTION=mysql
DB_HOST=mariadb
DB_PORT=3306
DB_DATABASE=testing
DB_USERNAME=sail
DB_PASSWORD=password

・・・(以下省略)・・・

テスト用データベースのマイグレーション

現在、テスト用データベースには、「todos」などの前回作成したテーブルがありません。

次のコマンドでシーダーまで含めて実行しましょう。

php artisan migrate:fresh --seed --env=testing

最後の「–env=testing」を忘れると「webapp」データベースの方が

マイグレーションされてしまうので、間違えないように注意します。

念のため、テスト用データベースのtodosテーブルにレコードがあるか確認します。

各自の好きな確認方法でかまいませんが、ここではMySQL CLIで確認していきます。

mysql -h mariadb -u sail -p
show databases;
use testing;
show tables;
select * from todos;

シーダーによってレコードが登録されていることが確認できました。

テストコード作成

次のコマンドを実行します。

php artisan make:test TodoTest

フォルダ [tests/Feature/] 内に、[TodoTest.php] が作成されます。

このファイルを開いてみると、次のようなコードが書かれています。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class TodoTest extends TestCase
{
    /**
     * A basic feature test example.
     */
    public function test_example(): void
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

14行目~19行目が、テスト時に実行される処理です。

ページや機能ごとにテストメソッドを作成していきます。

テストメソッド名は「test_」で始めます。

その後ろはテスト内容がわかりやすい名前を付けます。

まずは、この状態でこのコードだけ自動テストを実行してみます。

php artisan test tests/Feature/TodoTest.php

無事、テストが通りました。

実行している処理は2個だけです(16行目、17行目)。

1.URL「/」(トップページ)のHTTPレスポンスを取得する。

2.HTTPレスポンスのステータスコードが「200」であることを確認する。

 →リダイレクトで「302」だとエラーになります。

では、実際にコードを追記していきましょう。

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
use App\Models\Todo;

class TodoTest extends TestCase
{
    /**
     * A basic feature test example.
     */
    public function test_index_can_get_todo_list(): void
    {
        Todo::truncate();
        $todos = Todo::factory()->count(5)->create();
        $response = $this->get(route('todo.index'))
                         ->assertSee('TODOリスト')
                         ->assertSee('新規登録')
                         ->assertOk();
        foreach ($todos as $todo) {
            $response->assertSee($todo->todo);
        }
    }

    public function test_retrieve_can_be_rendered(): void
    {
        Todo::truncate();
        $todos = Todo::factory()->count(5)->create();
        foreach ($todos as $todo) {
            $this->get(route('todo.detail', ['id' => $todo->id]))
                 ->assertSee('TODO詳細')
                 ->assertSee('[編集]')
                 ->assertSee('[削除]')
                 ->assertSee('todo一覧')
                 ->assertSee('やること: ' . $todo->todo)
                 ->assertSee('状態:' . (1 == $todo->done ? '完了' : ''))
                 ->assertOk();
        }
    }

    public function test_create_can_be_rendered(): void
    {
        $this->get(route('todo.create'))
             ->assertSee('TODO新規登録')
             ->assertSee('やること:')
             ->assertSee('登録')
             ->assertSee('取消')
             ->assertOk();
    }

    public function test_store_can_store(): void
    {
        $todo = Todo::factory()->definition();
        $this->post(route('todo.store'), $todo)
             ->assertValid()
             ->assertRedirect(route('todo.index'));
        $this->get(route('todo.index'))
             ->assertSee($todo['todo']);
    }

    public function test_edit_can_be_rendered(): void
    {
        Todo::truncate();
        $todos = Todo::factory()->count(5)->create();
        foreach ($todos as $todo) {
            $this->get(route('todo.edit', ['id' => $todo->id]))
                 ->assertSee('TODO編集')
                 ->assertSee('取消')
                 ->assertSee('やること:')
                 ->assertSee($todo->todo)
                 ->assertSee('状態:')
                 ->assertSee('未完')
                 ->assertSee('完了')
                 ->assertSee('登録')
                 ->assertOk();
       }
    }

    public function test_update_can_update(): void
    {
        Todo::truncate();
        $todos = Todo::factory()->count(5)->create(['done' => 0]);
        $id = 2;
        $todo = 'update:' . $todos[$id]->todo;
        $this->patch(route('todo.update', ['id' => $id]), [
                'todo' => $todo,
                'done' => 1,
             ])
             ->assertValid()
             ->assertRedirect(route('todo.detail', ['id' => $id]));
        $this->get(route('todo.index'))
             ->assertSee($todo);
    }

    public function test_destroy_can_destroy(): void
    {
        Todo::truncate();
        $todos = Todo::factory()->count(5)->create();
        $id = 2;
        $this->delete(route('todo.destroy', ['id' => $id]))
             ->assertRedirect(route('todo.index'));
        $todos = Todo::all();
        foreach ($todos as $todo) {
            $this->assertTrue($todo->id !== $id);
        }
    }
}

細かい説明は長くなるので、記事を分割しました。

アサーションと呼ばれる確認用のメソッドは、公式サイトで確認してください。

テスト実行

では、テストを実行してみましょう。

php artisan test tests/Feature/TodoTest.php

オールグリーンです。気持ちイイですね。

では、他のテストもまとめて実行しましょう。

php artisan test

オールグリーンです。これで気持ちよく眠れます。

エラーが出た際の処理は次回を予定しています。

お疲れさまでした。

コメント

タイトルとURLをコピーしました