laravelpro_テストとデバッグ

15テストとデバッグ

テストについて

ここまでメモアプリを作成してきました。これで完成……と行きたいところですが、その前に全ての機能が正常に動くかを確認する必要があります。

テストは先ほどまでのように実際に人が動かしながら動作を確認する手動テストだけでなく、プログラムに任せる自動テストがあります。

laravelにおける自動テストは大きく分けると「ユニットテスト」「フィーチャーテスト」「ブラウザテスト」の3つですが、今回は「ユニットテスト」と「フィーチャーテスト」の書き方を学んでいきます。

テスト前の準備

テストを作成する前に準備をしていきましょう。

テストでは開発環境のデータに影響されないよう、別のDB等に接続してテストします。

(のちに説明しますが、テスト中にデータが追加されたり、テーブルのデータを削除したりもします。)

毎回接続先を変えるわけにもいかないので、テストの時に使う環境変数を設定しておき、テストの際にはそちらを読み込むようにします。

今回はDBのスキーマをもう一つ作り、そこをテスト用に動作させます。MySqlに接続し、スキーマを作成しましょう。

CREATE SCHEMA `laravel_test` ;

次にテスト用の環境変数ファイルを作成します。

.envファイルを複製し、ファイル名を「.env.testing」に変更します。

.env.testingの中身のAPP_ENVとDB_DATABASEをそれぞれ

APP_ENV=test
DB_DATABASE=laravel_test

に変更します。

次に先ほど作成したスキーマにマイグレーションを実行します。

php artisan migrate --env=testing 

–envオプションで使用する環境変数を指定することができます。

それではテストできる環境が整ったので、既にあるテストを動かしてみましょう。artisanコマンドでテストを実行することが出来ます。

php artisan test

実行するといくつか結果が出てきたと思います。

まずトータルの結果を確認していきます。

(結果の値が違うかもしれませんが、気にしないでください)

1つのテスト関数につき1つのテストとします。成功しているテストがpassed、失敗している場合はfaliedで表示されます。assertionsはテスト内で実行している(このあと説明する)アサートの数を指しています。

次に失敗したテストの内容を確認します。

とあります。このテストコードは「’/’にアクセスし、正常にレスポンスが返ってきたか」を確認しています。

get関数で指定したルートへの(疑似的な)リクエストを行ないます。

そしてassertStatus関数でレスポンスのステータスを確認します。

アサート(assert)はテストが期待通りに動作していることを検証するために使用される関数です。アサート関数については種類がいくつかあるので、時間があれば調べてみてください。

~で学んだようにレスポンスのステータスが200の場合は正常に返ってきていることを示しているので、「正常に遷移できたかどうか」をテストするコードとなります。

しかし、実際には302(リダイレクト)が返ってきているためエラーとなっています。

先ほどまでで作成したroutes/web.phpを確認してみると

routes/web.php

Auth::routes(); Route::group(['middleware' => 'auth'], function () {
    Route::get('/', 'App\\Http\\Controllers\\MemoController@show');
    Route::post('/add', 'App\\Http\\Controllers\\MemoController@add');
    Route::post('/delete', 'App\\Http\\Controllers\\MemoController@delete');
    Route::get('edit/{edit_id}', 'App\\Http\\Controllers\\MemoController@getEdit');
    Route::post('update', 'App\\Http\\Controllers\\MemoController@postEdit');
});

‘/’にアクセスする際にログインしていることを前提としています。

そのため、ログインせずにリクエストするとログイン画面にリダイレクトされてしまっているのでエラーとなっています。

あくまでも「テスト作成時に想定されていた内容」でテストを実行するため、テストを修正すべきなのか、コードを修正するべきなのかは考える必要があります。

このようにコマンドひとつでテストを実行することが出来ます。

ユニットテスト作成

まずユニットテストを作成してみましょう。ユニットテストとは、単体テストとも呼ばれ小さな機能ひとつひとつを確認するテストになります。

php artisan make:test CommonTest --unit

php artinsan make:test

にするとtinkerみたいに対話型で作成してくれます。名前を指定するとオプションがない限り強制でFeatureテストが作られます。

作成したテストはtestsフォルダに格納されます。

ユニットテストの特徴として動作が早いものの、Laravelアプリケーションを起動起動しないためDBをつかった関数等がテスト出来ない等の制限があります。

共通ロジック等を作った場合はこちらでテストを作成します。

フィーチャーテストの作成

laravelで主に使われるのは「フィーチャーテスト」です。こちらは機能テストとも呼ばれます。urlへのアクセスから表示までをテストすることが出来ます。

それではフィーチャーテストを新規で作成してみましょう。

php artinsan make:test MemoControllerTest

作成したテストはtests/Featureフォルダに格納されます。

先ほど例に出したようなテストが生成されているはずです。ただ、このまま実行すると先ほどのようにエラーになってしまいます。

今回はログイン後の動作確認をするため「ユーザーを作成する→ログインした状態にする」コードを書きます。

public function test_example(): void
    {
        $user = User::factory()->create(); // 追記
        $response = $this->actingAs($user)->get('/'); // 修正

        $response->assertStatus(200);
    }

まずモデルのファクトリーメソッドを使いユーザーデータを生成します。

actingAsメソッドではテスト上でログイン状態を再現する関数です。この関数を用いてログイン状態にした後リクエストを送ります。

それでは作成したテストを動かしてみましょう。今回は作成したテストだけ実施したいのでファイルを指定します。

php artisan test tests/Feature/MemoControllerTest.php

OKになりました。

ではもう一つ関数を足してテストしてみましょう。

public function test_add(): void

    {

        $user = User::factory()->create();

        $response = $this->actingAs($user)->post('/add',[

            'memo_text' => 'test memo',

        ]);

        // リダイレクト先を確認

        $response->assertStatus(302)

        ->assertRedirect('/');

        // 追加したメモがDBに保存されているか確認

        $this->assertDatabaseHas('memos', [

            'user_id' => $user->id,

            'content' => 'test memo',

        ]);

        // ホームに追加したメモが表示されているか確認

        $this->get('/')->assertSeeText('test memo');

    }

このテスト関数では「メモ追加」のテストを行っています。

ログイン後にリクエストメッセージ「memo_text」に’test memo’を入れてリクエストを送ります。リクエスト自体は登録処理後にリダイレクトするのでステータスコードが302かどうかを検証します。

assertDatabaseHas関数でDBに登録されているか、再度遷移しassertSeeText関数で’test memo’が表示されているかを検証しています。

さて、ここで何度可実行してみてDBを確認してみると

use laravel_test;
SELECT count(*) FROM memos;

データが増えていることが分かります。これはテスト中にユーザーデータやメモを作成しているためです。

例えばタイムライン画面のテストを作る際、適当にデータを入れて全て表示しているか確認しようとすると、毎回表示される数が異なったりと正しいテストが出来ません。

そのためにテストケースごとにDBをリセットさせてしまいましょう。(テスト内でユーザーを毎回作っていたのはそのためです)

class MemoControllerTest extends TestCase
{
    use RefreshDatabase; // 追記

※注意※これを設定して実行するとDB上のデータが全て消えてしまいます。テスト作成時に不安な場合はこれをコメントアウトした状態でテストファイルを指定して実行し、想定したDBやスキーマ等とつながっているか確認しましょう。

もう一度実行してみます。

php artisan test tests/Feature/MemoControllerTest.php

実行結果を確認しDBを確認するとデータが全て消えていることが分かります。

use laravel_test;
SELECT count(*) FROM memos;

laravelではこのようにテストを作成していきます。

他にも色々なアサートがあるので余裕があれば確認してみましょう。

また今回は触れませんでしたが、Pestを使ったテストやブラウザテストを実施するDusk等もあるので、今はまだテストに興味が持てないかもしれませんが、余裕が出来たら学習してみましょう。


投稿日

カテゴリー:

投稿者:

タグ:

コメント

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です