RefreshDatabase
はマイグレーションを使う場合にしか使えません。そういうときは DatabaseTransactions
を使うといいよというお話です。
なお、古くからの Laravel 遣いには、目新しさが微塵も無い記事だと思うので、スルーしていただければと思います。
前提
- Laravel 6.8.10
RefreshDatabaseもいいけど...
Laravel で DB に関するテストをする際は RefreshDatabase
を使うのがテッパンだと思います( ドキュメント )。
しかし、 RefreshDatabase
はテストが終わったらマイグレーションを再度実行するというものなので、 マイグレーションを使わない場合 (例えば、既存 DB を使う場合)には適していません。1
そこでDatabaseTransactionsを使おう
Illuminate\Foundation\Testing\DatabaseTransactions
は、 テストを実行しているあいだだけ有効なトランザクション を作ってくれるトレイトです。具体的には、 setUp()
したタイミングでトランザクションを作成し、 tearDown()
したタイミングでロールバックします。2
実は、Laravel 5.4 の ドキュメント には記載があるのですが、 5.5 で RefreshDatabase
が追加されたからか、ドキュメントからは削除されてしまったようです。
1つ注意しないといけないのは、 DatabaseTransactions
は、何も設定しなければ、デフォルトの DB 接続 3 に対してトランザクションを作るということです。
もし、デフォルト以外の DB 接続に対してトランザクションを作りたい場合は、テストクラスにプロパティ $connectionsToTransact
を作り、 config/database.php
に設定した DB 接続名を指定することができます。
namespace Tests\Unit;
use Tests\TestCase;
use App\Http\Services\SampleService;
use Illuminate\Support\Facades\DB;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class SampleServiceTest extends TestCase
{
// テスト実行中のみ有効なトランザクションを設定する。
use DatabaseTransactions;
// トランザクションを設定する DB 接続名を指定する。
private $connectionsToTransact = [ 'mysql_slave' ];
public function setUp(): void
{
parent::setUp();
// トランザクションを設定した DB に対して、テストデータを INSERT する。
DB::connection('mysql_slave')->table('d_products')
->insert([
[
'name' => 'りんご',
],
[
'name' => 'オレンジ',
],
]);
}
/**
* @test
*/
public function 製品一覧を取得できること()
{
$service = new SampleService();
$result = $service->fetchProducts();
$expected = [
(object)['name' => 'りんご'],
(object)['name' => 'オレンジ'],
];
$this->assertEquals($expected, $result);
}
}
注意点
Laravel 5.4 で手軽にテストを書こう! や laravelでDBテストコードを書く前の設定すべきこと で指摘されているように、 AUTO_INCREMENT
の設定値は変わってしまいます。
終わりに
RefreshDatabase
しか無いのか... と軽く絶望していたときに、 DatabaseTransactions
を見つけたときは、本当に嬉しかったです。はい。
-
そりゃ、私だって、あんな メチャクチャな テーブル定義の DB を使いたくはないですよ。どうせ、Laravel で作るなら、心機一転、全部作り直したい。でも、 大人の事情 という例のアレのせいで、そうできないんですよ!(溜息) ↩
-
Illuminate\Foundation\Testing\TestCase
のsetUpTraits()
でDatabaseTransactions
クラスを使っている場合は、そのbeginDatabaseTransaction()
をコールしています。beginDatabaseTransaction()
では、プロパティ$beforeApplicationDestroyedCallbacks
にロールバックと DB 接続を切断する関数を追加しています。ここで追加された関数がtearDown()
でコールされます。 ↩ -
config/database.php
のdefault
の設定値を参照します。.env
でDB_CONNECTION
が設定されていれば、それが優先されます。設定されていなければ、'mysql'
が使われます。 ↩