概要
RefreshDatabaseをPHP8系で利用するとエラーになり、ユニットテストができないようです。
対処方法はいくつか考えられますが、おすすめの2パターンを紹介します。
プロジェクトやテスト内容に応じて、お好きな方をお使いいただければと思います。
もし、この方法がいいよ、などあればコメントにて教えてください。
環境
- PHP 8.0.9
- Laravel Framework 8.83.27
- PHPUnit 9.5.28
RefreshDatabaseを使うと遭遇するエラー
RefreshDatabaseを使うと以下のエラーに遭遇します。
PDOException: There is no active transaction
/var/www/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php:279
/var/www/vendor/laravel/framework/src/Illuminate/Database/Concerns/ManagesTransactions.php:254
/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/RefreshDatabase.php:105
/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:246
/var/www/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:158
このエラーについては、[8.x] Fix error PDOException: There is no active transaction でも議論されているようです。
解決策
1. TraitをRefreshDatabase
からDatabaseMigrations
に変える
変更内容
namespace Tests\Unit;
- use Illuminate\Foundation\Testing\RefreshDatabase;
+ use Illuminate\Foundation\Testing\DatabaseMigrations;
use Tests\TestCase;
class SampleTest extends TestCase
{
- use RefreshDatabase;
+ use DatabaseMigrations;
エラーは出なくなりますが、DatabaseMigrationsはmigrate:fresh
を都度行います。
migrate:fresh
コマンドは、データベースからすべてのテーブルを削除したあと、migrateコマンドを実行します。そのため、処理に時間がかかります。
実行結果
./vendor/bin/phpunit tests/Unit/SampleTest.php
PHPUnit 9.5.28 by Sebastian Bergmann and contributors.
...... 6 / 6 (100%)
Time: 00:36.298, Memory: 22.55 MB
OK (6 tests, 6 assertions)
2. setUp()
でmigrate
とtruncate
を行う
変更内容
ユニットテスト内でsetUp()
をオーバーライドして、migrate
の実行とテストに必要なテーブルのtruncate
を行います。
namespace Tests\Unit;
use App\Models\Sample;
use Tests\TestCase;
class SampleTest extends TestCase
{
public function setUp(): void
{
parent::setUp();
$this->artisan('migrate');
Sample::truncate();
}
migrate
は未処理のマイグレーションのみ実行します。
テーブルの初期化をする必要がある場合は対象となるテーブルのみtruncate
しましょう。
※ 処理済みのマイグレーションファイルを編集など行なった場合にもマイグレーションの再実行はされないので注意が必要です。
実行結果
./vendor/bin/phpunit tests/Unit/SampleTest.php
PHPUnit 9.5.28 by Sebastian Bergmann and contributors.
...... 6 / 6 (100%)
Time: 00:12.223, Memory: 22.55 MB
OK (6 tests, 6 assertions)
1.のDatabaseMigrationsを利用した場合と比較すると約3倍早いですね。。。
まとめ
個人的には、開発初期段階や比較的小さいプロジェクトであればDatabaseMigrations
を利用する方法で良いと思います。しかし、中規模以上のプロジェクトでマイグレーションするテーブルやファイルが多い場合、ユニットテストに時間がかかり過ぎてしまいかなり非効率です。この辺りはプロジェクトに応じてご検討いただければと思います。