隨著 migration 檔案越來越多,測試速度越來越慢,即使用 SQLite In-Memory Database 也一樣,因為 migration 是一個檔案一個檔案跑的。

schema:dump 不支援 In-Memory Database
Laravel 8 提供了 php artisan schema:dump 指令,能把所有 migration 合併成一個 SQL 檔案。但查看原始碼後發現,SQLite In-Memory Database 不支援這個指令。
網路上有人建議用 DB::unprepared(file_get_contents("path/file.sql")) 手動載入,實測可行但速度反而更慢。
用 PDO::exec 直接載入 schema
關鍵是改用 PDO 的 exec 而不是 DB::unprepared:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
| namespace Tests;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUpTraits()
{
// 必須在 parent::setUpTraits 之前
$uses = array_flip(class_uses_recursive(static::class));
$schema = database_path('schema/sqlite-schema.dump');
if (isset($uses[RefreshDatabase::class]) &&
$this->usingInMemoryDatabase() &&
File::exists($schema)
) {
DB::connection()->getPdo()->exec(File::get($schema));
}
parent::setUpTraits();
}
}
|
實測從 2:21.979 秒降到 18.457 秒,快了 7 倍。
抽成可重用的 Trait
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| namespace Tests\Traits;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\File;
trait RefreshInMemoryDatabase
{
public function loadSchemaToInMemoryDatabase(): array
{
$uses = array_flip(class_uses_recursive(static::class));
$schema = database_path('schema/sqlite-schema.dump');
if (isset($uses[RefreshDatabase::class]) &&
$this->usingInMemoryDatabase() &&
File::exists($schema)
) {
DB::connection()->getPdo()->exec(File::get($schema));
}
return $uses;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use Tests\Traits\RefreshInMemoryDatabase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
use RefreshInMemoryDatabase;
protected function setUpTraits()
{
// 必須在 parent::setUpTraits 之前
$this->loadSchemaToInMemoryDatabase();
parent::setUpTraits();
}
}
|