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_jobs
・jobs
・migrations
以外は、
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指定でテストしている場合には注意が必要です