108
87

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

laravelでDBテストコードを書く前の設定すべきこと

Last updated at Posted at 2018-03-26

データベースのテストをする際には、テスト用のDBを用意して、そのDBでテストした方が良い。

理由

テストDBを用意して、テストを実行する際、
DatabaseMigrationsDatabaseTransactionsを使ってもDBに全く影響を与えないわけでは無いです。

AUTO_INCREMENTの値など、一部は影響を受けてしまいます
Laravel 5.4 で手軽にテストを書こう! | 株式会社インフィニットループ技術ブログ

実際に試してみました。

  1. use DatabaseTransactions;が無い状態で、AUTO_INCREMENTのカラムがあるレコードを追加するコードのあるテストを実行(※以降テスト)
  2. use DatabaseTransactions;がある状態テストを実行
  3. use DatabaseTransactions;が無い状態テストを実行

そうするとAUTO_INCREMENTのカラムが連番にリませんでした。

テストをすることで少しでも本番DBなどに影響を与えてしまうのは良くないので、テストする時用でDBを切り替えてた方が良いと思いました。

データベースのテスト 5.4 Laravel

テストDBでのテスト方法

テスト用のDBを作成する。

hoge_testing
※surfixに _testingをつけるとテストDBだということが分かりやすい。

envファイルでDBを切り替えるパターン

開発環境、本番環境、ローカル環境などでテストDB名が違う場合は、このパターンを使うのが良いと思う。

テスト用のenvファイルを作る

ファイル名
.env.testing

DB名の箇所だけ書き換える

DB_DATABASE=hoge_testing

テストDBに対してmigrateを実行する方法

php artisan migrate --seed --env=testing

--env=testingをつけることで.env.testingのenvファイルを読んでmigrateを実行する事ができる。
Laravel5 で別環境(APP_ENV)で artisan コマンドを実行 - Qiita

テストコード内でmigrate:refreshなどを実行しているのであれば、コマンドでのmigrateの実行は不要かと思います。

phpunit.xmlでDBを切り替えるパターン

phpunit.xmlファイル内に<env name="DB_DATABASE" value="hoge_testing"/>を追加。
追加する箇所は以下の通りです。

<php>
        <env name="APP_ENV" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="DB_DATABASE" value="hoge_testing"/>
</php>

[Laravel 5.2] Laravelでtest用DBにmigrateする方法 - Qiita

コマンドからmigrateを実行する場合

config/database.phpのmysqlの設定コピーして、databaseの箇所だけテストDBのDB名に書き換える。

'mysql_testing' => [
            'driver' => 'mysql',
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => 'hoge_testing',
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'strict' => true,
            'modes' => [

            ],
            'engine' => null,
        ],

後は以下のコマンドを実行すればテストDBに対してmigrate:refreshを実行することが出来る。

php artisan migrate:refresh --database=mysql_testing

[Laravel 5.2] Laravelでtest用DBにmigrateする方法 - Qiita

config をクリアする。

php artisan config:clear

このコマンドを実行せずにArtisan::call('migrate:refresh');など実行があるテストを実行したりすると、本番DBのデータが飛んだりするので要注意です。

DBの初期状態でデータベースのテストをする場合

テストクラスに以下メソッドを追加。

public function setUp() {
    parent::setUp();
    Artisan::call('migrate:refresh');
    Artisan::call('db:seed');
}

migrate:refreshを実行する際はmigrationファイルのdownメソッドにupメソッドが行った操作を元戻す処理 を書いておく必要があります。
https://readouble.com/laravel/5.3/ja/migrations.html

外部キー制約がある場合

以下のエラーが出る時があります。

SQLSTATE[23000]: Integrity constraint violation: 1217 Cannot delete or update a parent row: a foreign key constraint fails 

以下の様にして一時的に外部キー制約を解除する。

public function down()
{
    Schema::disableForeignKeyConstraints();
    Schema::dropIfExists('user');
    Schema::enableForeignKeyConstraints();
}

Laravel5でテスト時にtesting設定を使う方法 - アルファブレンド プログラミングチップス

laravelのバージョンが5.5であればRefreshDatabase;が使える。
use RefreshDatabase;を追加することで
テスト前にMigrationとSeederが実行される。
LaravelでHTTPテスト - Qiita

テストを実行

'phpunit'をコマンドで実行

おまけ

setUpBeforeClass以外の方法でクラスで一回だけ実行するメソッドを作る方法

migrate:refreshdb:seedを、setUpメソッドに記述すると、テストにかかる時間が結構長くなってしまうので、クラスで一回だけ実行すれば場合はsetUpBeforeClassというメソッド内で実行すると良いようです。しかしsetUpBeforeClass内でenv()logger()などのlaravelで用意してくれているhelperは使えませんでした。
以下の様な処理がしたかったがenvが呼べない。

    public static function setUpBeforeClass()
    {
        if(env('DB_DATABASE_TESTING') == 'hoge_testing'){
            Artisan::call('migrate:refresh');
            Artisan::call('db:seed');
            self::insertTestData();
        }
    }

なのでsetUpメソッドを一回のみ実行するようにしました。

private static $isSetup = false;

    public function setUp()
    {
        parent::setUp();
        if(env('DB_DATABASE_TESTING') == 'hoge_testing' && self::$isSetup === false){
            Artisan::call('migrate:refresh');
            Artisan::call('db:seed');
            self::$isSetup = true;
        }
    }

もっといい方法あるよって方は教えてください。

108
87
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
108
87

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?