イノベーション エンジニアブログ


株式会社イノベーションのエンジニアたちの技術系ブログです。ITトレンド・List Finderの開発をベースに、業務外での技術研究などもブログとして発信していってます!


このエントリーをはてなブックマークに追加

Laravelでテストする前に行ったテストDBの準備

どうも、小柳津です。

最近ようやく自社のプロダクトにもテストを書くようになってきました。
その時テストDBを準備のためにすることを予習していたので、行ったことを書いていきます。

実行環境

  • Laravel: 5.7

  • MySQL : 8.0

  • PHP: 7.1

  • PHPUnit: 7.3

設定方法

DBの準備自体は割愛します。
LaravelのテストDBを用意をしたあとに .env.testing を用意します。
これはデフォルトで用意されている phpunit.xml に以下の設定がされているためです。(一部抜粋)

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="BCRYPT_ROUNDS" value="4"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_DRIVER" value="array"/>
    </php>

これはPHPUnitを実行時には通常の envファイルの設定を見るのではなく、
APP_ENVのvalueに指定される値を付け加えた .env.{APP_ENVのvalue} を仕組みになっているからです。

用意した .env.testing (一部抜粋)

APP_ENV=test

DB_CONNECTION=mysql
DB_HOST={テストDBのホスト}
DB_PORT={テストDBのポート}
DB_DATABASE={テストDBのデータベース}
DB_USERNAME={テストDBのユーザーネーム}
DB_PASSWORD={テストDBのパスワード}

もともとあった開発環境用の .env (一部抜粋)

APP_ENV=local

DB_CONNECTION=mysql
DB_HOST={開発環境のDBのホスト}
DB_PORT={開発環境のDBのポート}
DB_DATABASE={開発環境のDBのデータベース}
DB_USERNAME={開発環境ののユーザーネーム}
DB_PASSWORD={開発環境ののパスワード}

これで2種類のenvファイルが出来上がりました。
それではPHPUnitを実行時に見ているenvファイルが .env.testing になっているか確認しましょう。

任意のテストクラスのsetUpメソッドに以下のようなものを書いてみます。

    public function setUp()
    {
        dd(env('APP_ENV'), env('DB_HOST'));
        parent::setUp();
    }

見ているenvファイルが .env.testing であれば上記で設定した値がコンソールに表示されます。

以下のテストコードをコマンドで実行します。
./vendor/bin/phpunit

test01.png

表示されていますね!
上記の設定でPHPUnit時のみenvファイルを切り替えることができました。

またLaravelは設定ファイルをキャッシュして高速化しているため、DBを扱うテストコードを実行する前に php artisan config:clear を実行することが勧められています。

これを忘れるとテストDBではないDBに変更が加わってしまうので気をつけましょう
私は以下のようなShell Scriptを用意して、それ経由でテストを実行しています。

#!/bin/bash

php artisan config:clear
./vendor/bin/phpunit

テストコード実行時

上記の設定を行ったことでDBを使用したコードのテストが行えるようになりました。

DBを活用したテストで気をつけることは各テストが後のテストに影響がないように、各テストの後にデータをもとに戻さなければならないことです。

上記は公式のドキュメントにもあるように、RefreshDatabaseトレイで解決することができます。
Laravel 5.7 データベースのテスト

RefreshDatabaseトレイトにより、マイグレーションに最適なアプローチが取れます。テストクラスにてこのトレイトを使えば、全てが処理されます。 RefreshDatabaseトレイトはテスト前に未実行のマイグレーションを実行し、テスト終了後にはデータベースが初期状態に復元します。
なので、DBを行うてすとコードはRefreshDatabaseトレイトを使用しましょう。

RefreshDatabaseトレイトを使用してDBを用いたテストを実行した場合

実行するテストコード

namespace Tests\Unit\Lesson;


use App\Eloquent\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
use Illuminate\Support\Facades\Schema;

class UserTest extends TestCase
{
    use RefreshDatabase;

    public function testFirstYaizuuuuNameUser()
    {
        $index = 0;

        $users = factory(User::class, 3)->create()
            ->each(function ($user) use (&$index) {
                $name = ['yaizuuuu', 'yaizu', 'yaizuu',];
                $user->name = $name[$index++];
                $user->save();
            });


        $actual = (new User)->firstYaizuuuuNameUser();

        $this->assertSame('yaizuuuu', $actual->name);
    }
}

実行後のDB

test02.png

テストコード内ではファクトリーを使用してテストデータを実行していますが、データは残っていませんね!

それに対してマイグレーションは実行されているので、テストDBにテーブルなどは残っています。

test03.png

RefreshDatabaseトレイトを使用しないでDBを用いたテストを実行した場合

実行するテストコードは先程と同じ。
ですが、そもそもマイグレーションを実行されないのでテーブルがエラーになってしまいます。

test04.png

テーブルが見つかりませんとなっていますね。

なのでテスト実行前に手動でマイグレーションを実行してテストを行いますが、テスト後もDBにデータが残ってしまっています。

test05.png

まとめ

  • .env.testingを作成

  • DBを扱うテストではRefreshDatabaseトレイトを使用する

とても簡単できて便利ですね!

今回はこれで失礼します。