はじめに
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:refresh
1にした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
コマンドがないからです ↩