LoginSignup
2
1

More than 1 year has passed since last update.

Laravel RefreshDatabase 高速化

Last updated at Posted at 2022-03-08

laravelのRefreshDatabaseが時間がかかるため、高速化したはなし

環境

laravel: v5.5.50
phpunit/phpunit: 5.7.27

原因

vender/laravel/framework/src/Illuminate/Foundation/Testing/RefreshDatabase.php
//...

    /**
     * Refresh a conventional test database.
     *
     * @return void
     */
    protected function refreshTestDatabase()
    {
        if (! RefreshDatabaseState::$migrated) {
            $this->artisan('migrate:fresh');

            $this->app[Kernel::class]->setArtisan(null);

            RefreshDatabaseState::$migrated = true;
        }

        $this->beginDatabaseTransaction();
    }

//...

$this->artisan('migrate:fresh'); に時間がかかる

データはcleanにしたいけど、migrationを1から実行したくない

対応

tests/Traits/RefreshDatabaseLite.php
<?php

namespace Tests\Traits;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
use Illuminate\Support\Facades\DB;

trait RefreshDatabaseLite
{
    use RefreshDatabase;

    /**
     * @return void
     */
    protected function refreshTestDatabase()
    {
        if (! RefreshDatabaseState::$migrated) {
            $this->artisan('migrate');

            DB::statement('set foreign_key_checks = 0');

            $tables = DB::connection()->getDoctrineSchemaManager()->listTableNames();

            foreach ($tables as $table) {
                if (in_array($table, [
                    'failed_jobs',
                    'jobs',
                    'migrations'
                ])) {
                    continue;
                }

                DB::table($table)->truncate();
            }

            DB::statement('set foreign_key_checks = 1');

            RefreshDatabaseState::$migrated = true;
        }

        $this->beginDatabaseTransaction();
    }
}

DB::connection()->getDoctrineSchemaManager()->listTableNames();でテーブル名を全て取得

laravelの固有のテーブルfailed_jobsjobsmigrations以外は、
DB::table($table)->truncate(); でtruncate処理

DB::statement('set foreign_key_checks = 0'); を実施しないと、
foreign keyの依存関係でtruncateがエラーになります

速度比較

  • RefreshDatabaseの場合
Time: 1.17 minutes, Memory: 36.00MB
  • RefreshDatabaseLiteの場合
Time: 15.1 seconds, Memory: 28.00MB

さいごに

use RefreshDatabaseしているため、
テストごとにロールバックされてcleanな状態でテストが実施可能です
※ auto incrementの採番は進んでしまうので、id指定でテストしている場合には注意が必要です

2
1
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
2
1