データベースのテスト
イントロダクション
Laravelは、データベース駆動型アプリケーションのテストを容易にするための、さまざまな便利なツールとアサーションを提供しています。さらに、Laravelのモデルファクトリとシーダーを使えば、アプリケーションのEloquentモデルとリレーションシップを使用して、テスト用のデータベースレコードを苦労なく作成できます。このドキュメントでは、これらの強力な機能について説明します。
各テスト後のデータベースリセット
先に進む前に、各テストの後にデータベースをリセットし、前のテストのデータが後続のテストに干渉しないようにする方法について説明します。Laravelに含まれるIlluminate\Foundation\Testing\RefreshDatabaseトレイトがこれを処理します。テストクラスでこのトレイトを使用するだけです。
1<?php 2 3use Illuminate\Foundation\Testing\RefreshDatabase; 4 5uses(RefreshDatabase::class); 6 7test('basic example', function () { 8 $response = $this->get('/'); 9 10 // ...11});
1<?php 2 3namespace Tests\Feature; 4 5use Illuminate\Foundation\Testing\RefreshDatabase; 6use Tests\TestCase; 7 8class ExampleTest extends TestCase 9{10 use RefreshDatabase;11 12 /**13 * A basic functional test example.14 */15 public function test_basic_example(): void16 {17 $response = $this->get('/');18 19 // ...20 }21}
Illuminate\Foundation\Testing\RefreshDatabaseトレイトは、スキーマが最新である場合、データベースのマイグレーションを実行しません。代わりに、データベーストランザクション内でテストを実行するだけです。したがって、このトレイトを使用しないテストケースによってデータベースへ追加されたレコードは、データベース内にまだ存在する可能性があります。
データベースを完全にリセットしたい場合は、代わりにIlluminate\Foundation\Testing\DatabaseMigrationsまたはIlluminate\Foundation\Testing\DatabaseTruncationトレイトを使用できます。しかし、これらのオプションはどちらもRefreshDatabaseトレイトよりも大幅に低速です。
モデルファクトリ
テスト時、テストを実行する前にデータベースにいくつかのレコードを挿入する必要がある場合があります。このテストデータを作成する際に各カラムの値を手動で指定する代わりに、Laravelではモデルファクトリを使用して、各Eloquentモデルのデフォルト属性のセットを定義できます。
モデルを作成するためのモデルファクトリの作成と利用に関する詳細は、完全なモデルファクトリのドキュメントを参照してください。モデルファクトリを定義したら、テスト内でそのファクトリを利用してモデルを作成できます。
1use App\Models\User;2 3test('models can be instantiated', function () {4 $user = User::factory()->create();5 6 // ...7});
1use App\Models\User;2 3public function test_models_can_be_instantiated(): void4{5 $user = User::factory()->create();6 7 // ...8}
シーダーの実行
機能テスト中にデータベースシーダーを使用してデータベースにデータを投入したい場合は、seedメソッドを呼び出します。デフォルトで、seedメソッドはDatabaseSeederを実行し、これは他のすべてのシーダーを実行します。あるいは、seedメソッドに特定のシーダークラス名を渡すこともできます。
1<?php 2 3use Database\Seeders\OrderStatusSeeder; 4use Database\Seeders\TransactionStatusSeeder; 5use Illuminate\Foundation\Testing\RefreshDatabase; 6 7uses(RefreshDatabase::class); 8 9test('orders can be created', function () {10 // Run the DatabaseSeeder...11 $this->seed();12 13 // Run a specific seeder...14 $this->seed(OrderStatusSeeder::class);15 16 // ...17 18 // Run an array of specific seeders...19 $this->seed([20 OrderStatusSeeder::class,21 TransactionStatusSeeder::class,22 // ...23 ]);24});
1<?php 2 3namespace Tests\Feature; 4 5use Database\Seeders\OrderStatusSeeder; 6use Database\Seeders\TransactionStatusSeeder; 7use Illuminate\Foundation\Testing\RefreshDatabase; 8use Tests\TestCase; 9 10class ExampleTest extends TestCase11{12 use RefreshDatabase;13 14 /**15 * Test creating a new order.16 */17 public function test_orders_can_be_created(): void18 {19 // Run the DatabaseSeeder...20 $this->seed();21 22 // Run a specific seeder...23 $this->seed(OrderStatusSeeder::class);24 25 // ...26 27 // Run an array of specific seeders...28 $this->seed([29 OrderStatusSeeder::class,30 TransactionStatusSeeder::class,31 // ...32 ]);33 }34}
別の方法として、RefreshDatabaseトレイトを使用する各テストの前に、Laravelにデータベースを自動的にシーディングするように指示することもできます。これは、ベーステストクラスに$seedプロパティを定義することで実現できます。
1<?php 2 3namespace Tests; 4 5use Illuminate\Foundation\Testing\TestCase as BaseTestCase; 6 7abstract class TestCase extends BaseTestCase 8{ 9 /**10 * Indicates whether the default seeder should run before each test.11 *12 * @var bool13 */14 protected $seed = true;15}
$seedプロパティがtrueの場合、テストはRefreshDatabaseトレイトを使用する各テストの前にDatabase\Seeders\DatabaseSeederクラスを実行します。ただし、テストクラスに$seederプロパティを定義することで、実行すべき特定のシーダーを指定できます。
1use Database\Seeders\OrderStatusSeeder;2 3/**4 * Run a specific seeder before each test.5 *6 * @var string7 */8protected $seeder = OrderStatusSeeder::class;
利用可能なアサーション
PestまたはPHPUnitの機能テストのために、Laravelはいくつかのデータベースアサーションを提供しています。以下でこれらの各アサーションについて説明します。
assertDatabaseCount
データベース内のテーブルに、指定された数のレコードが含まれていることをアサートします。
1$this->assertDatabaseCount('users', 5);
assertDatabaseEmpty
データベース内のテーブルにレコードが含まれていないことをアサートします。
1$this->assertDatabaseEmpty('users');
assertDatabaseHas
データベース内のテーブルに、指定されたキー/値のクエリ制約に一致するレコードが含まれていることをアサートします。
1$this->assertDatabaseHas('users', [3]);
assertDatabaseMissing
データベース内のテーブルに、指定されたキー/値のクエリ制約に一致するレコードが含まれていないことをアサートします。
1$this->assertDatabaseMissing('users', [3]);
assertSoftDeleted
assertSoftDeletedメソッドは、指定されたEloquentモデルが「ソフトデリート」されていることをアサートするために使用します。
1$this->assertSoftDeleted($user);
assertNotSoftDeleted
assertNotSoftDeletedメソッドは、指定されたEloquentモデルが「ソフトデリート」されていないことをアサートするために使用します。
1$this->assertNotSoftDeleted($user);
assertModelExists
指定されたモデルがデータベースに存在することをアサートします。
1use App\Models\User;2 3$user = User::factory()->create();4 5$this->assertModelExists($user);
assertModelMissing
指定されたモデルがデータベースに存在しないことをアサートします。
1use App\Models\User;2 3$user = User::factory()->create();4 5$user->delete();6 7$this->assertModelMissing($user);
expectsDatabaseQueryCount
expectsDatabaseQueryCountメソッドは、テストの開始時に呼び出し、テスト中に実行されると予想されるデータベースクエリの総数を指定します。実際に実行されたクエリの数がこの期待値と完全に一致しない場合、テストは失敗します。
1$this->expectsDatabaseQueryCount(5);2 3// Test...