はじめに
LumenでDBを使用したテストを行う際にDBの初期化を行うために Laravel\Lumen\Testing\DatabaseMigrations というトレイトが提供されています。これは基本的には開始時にmigrateを行い終了時にmigrate:rollbackすることできれいにする、という動作をしますが、テストが異常終了するときちんとrollbackできずDBに中身が残ることがあって、その状態になると次回のテストが中身が残った状態で開始されてしてしまいテスト内容によっては失敗してしまいます。
これはDatabaseMigrations trait doesn't revert DB inserts and deletes #775で報告されている問題です。本家のLaravelでは開始時にmigrateではなくmigrate:freshを行うようになっていてこの問題は解決済みですが、Lumenには取り込まれていません。
Laravelの修正を取り込む
Lumenはそのうち直るとしてもいつになるかわからないので、今できる対処としてLaravel\Lumen\Testing\DatabaseMigrationsが開始時に実行するmigrateコマンドをmigrate:refresh1にしたMyDatabaseMigrationsトレイトを作ってそれを使うようにしようというのはすぐ思いつきます。
そこで最初以下のようなものを作ってみたのですがうまくいきませんでした。migrationが全く行われません。
trait MyDatabaseMigrations
{
public function runDatabaseMigrations()
{
$this->artisan('migrate:refresh');
$this->beforeApplicationDestroyed(function () {
$this->artisan('migrate:rollback');
});
}
}
呼び出し元を調べたところ、runDatabaseMigrationsを呼ぶかどうかはLaravel\Lumen\Testing\DatabaseMigrationsトレイトをuseしているかどうかで判定していました。(Laravel\Lumen\Testing\TestCaseクラスのsetUpTraitsメソッド)
protected function setUpTraits()
{
$uses = array_flip(class_uses_recursive(get_class($this)));
if (isset($uses[DatabaseMigrations::class])) {
$this->runDatabaseMigrations();
}
...
}
従って正解はさらにLaravel\Lumen\Testing\DatabaseMigrationsをuseするようにして以下のようになります。
trait MyDatabaseMigrations
{
use \Laravel\Lumen\Testing\DatabaseMigrations;
public function runDatabaseMigrations()
{
$this->artisan('migrate:refresh');
$this->beforeApplicationDestroyed(function () {
$this->artisan('migrate:rollback');
});
}
}
runDatabaseMigrationsしかないトレイトをuseしてその唯一のメソッドがいきなり上書きされてしまうわけですが、そのトレイトをuseしたという事実が重要です。
さらによくよく見ると、beforeApplicationDestroyedで行っているロールバックも開始時にmigrate:refreshを行うという前提なら無駄な気がします。むしろテスト後にDBの中身をちょっと見られて便利でもあるので自分は削ってしまいました。
最終的には以下のようなものを使用しています。
trait MyDatabaseMigrations
{
use \Laravel\Lumen\Testing\DatabaseMigrations;
public function runDatabaseMigrations()
{
$this->artisan('migrate:refresh');
}
}
-
migrate:freshではなくmigrate:refreshになっているのは、Lumenにはいまのところmigrate:freshコマンドがないからです ↩