結論
- テスト始動に70秒かかっていたのが一瞬で始まるようになった
migrate:fresh
ではなくmigrate
を使う
背景
- LaravelでRDB絡みのテストをするとき、いつも
RefreshDatabase
トレイトを使っている
- migrationの数が増えるにつれ、テストが耐え難い遅さになってきた
参考
動画
原因
RefreshDatabase
トレイトのphp artisan migrate:fresh
を実行している部分が遅い
コード
solution -- migrate:freshではなくmigrateを使用する
migrate:freshとmigrateの違い
migrate:fresh
では、テーブルを削除して1からmigrate
を行う
migrate
では、マイグレーション済みのテーブルについては処理をスキップする
- テーブルを削除しなければならないケースは少ない
- ふだんcode-test-commitをぐるぐる回すぶんには
migrate:fresh
は不要で、migrate
で十分
migrate使用による高速化
sample code -- RefreshDatabaseトレイトをoverrideする
- 基本の考え方は
DatabaseTransactions
トレイト + setUpでmigrate
実行
- が、いろいろ共通化したい
- migrateの実行
- 複数DBコネクション使用時、すべてをrollback対象にする
protected $connectionsToTransact
メンバに設定
RefreshDatabase
トレイトのほうが完成像に近いので、こちらを手を加えて「オレオレRefreshDatabaseトレイト」を作る
<?php
declare(strict_types=1);
namespace Tests\Concerns;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\RefreshDatabaseState;
use App\Console\Kernel;
trait RefreshDatabaseLite
{
use RefreshDatabase;
@see @connectionsToTransact
protected $connectionsToTransact = [
'mysql_foo',
'mysql_bar',
'mysql_secure',
];
@return
protected function refreshTestDatabase()
{
if (!RefreshDatabaseState::$migrated) {
$this->artisan('migrate');
$this->app[Kernel::class]->setArtisan(null);
RefreshDatabaseState::$migrated = true;
}
$this->beginDatabaseTransaction();
}
}
- 個々のテストケース側で、
Illuminate\Foundation\Testing\RefreshDatabase
の代わりにTests\Concerns\RefreshDatabaseLite
をuseすればOK
- 「トイレ行く前にテスト起動しとく」といった涙ぐましい時短はもはや必要ない
- 世界は救われた