Database Testing
Table of Contents
Introduction
Laravel は、database 駆動 types の application の test を容易にするための、様々な便利なツールとアサーションを提供しています。加えて、Laravel モデルの factories ーやシーダーは、application の Eloquent モデルやリレーションシップを使用した testdatabase レコードの作成を簡単にします。以下のドキュメンテーションでは、これらの強力な機能について全て説明します。
テストのたびに Database をリセットする
これ以上進む前に、各テストの後にどのように reset を行い、前のテストの data が次のテストに干渉しないように database をリセットするかについて説明しましょう。Laravel に含まれる Illuminate\Foundation\Testing\RefreshDatabase
トレイトがこれを処理してくれます。テストの class でこのトレイトを使うだけです:
<?php
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('basic example', function () {
$response = $this->get('/');
// ...
});
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* A basic functional test example.
*/
public function test_basic_example(): void
{
$response = $this->get('/');
// ...
}
}
Illuminate\Foundation\Testing\RefreshDatabase
トレイトは、 schema が最新の場合、 database を migrate しません。代わりに、 database transaction 内でテストのみを実行します。そのため、このトレイトを使用しないテストケースによって database に追加されたレコードは、 database に存在し続ける可能性があります。
あなたが database を完全に reset したい場合は、代わりにIlluminate\Foundation\Testing\DatabaseMigrations
または Illuminate\Foundation\Testing\DatabaseTruncation
の特性を使用することができます。しかし、これらの options は、RefreshDatabase
の特性よりもかなり遅いです。
Model Factories
testing を行う際には、testing を実行する前に database にいくつかのレコードを挿入する必要があるかもしれません。testingdata を作成する際に各列の value を手動で指定する代わりに、Laravel では、Eloquent modelsごとに一連の default 属性を定義することができます。これはmodelfactory ーを使用して行います。
modelfactory ーの作成と活用について更に詳しく学ぶためには、完全なmodel factory ドキュメンテーションをご覧ください。model factory を定義すると、test 内で factory を活用して models を作成することができます。
use App\Models\User;
test('models can be instantiated', function () {
$user = User::factory()->create();
// ...
});
use App\Models\User;
public function test_models_can_be_instantiated(): void
{
$user = User::factory()->create();
// ...
}
Running Seeders
database seedersを使用して feature テスト中に database を満たしたい場合、seed
method を呼び出すことができます。default では、seed
method はDatabaseSeeder
を実行し、他のすべてのシーダーを実行するはずです。または、特定のシーダー class 名をseed
method に渡すこともできます:
<?php
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
test('orders can be created', function () {
// Run the DatabaseSeeder...
$this->seed();
// Run a specific seeder...
$this->seed(OrderStatusSeeder::class);
// ...
// Run an array of specific seeders...
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
});
<?php
namespace Tests\Feature;
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class ExampleTest extends TestCase
{
use RefreshDatabase;
/**
* Test creating a new order.
*/
public function test_orders_can_be_created(): void
{
// Run the DatabaseSeeder...
$this->seed();
// Run a specific seeder...
$this->seed(OrderStatusSeeder::class);
// ...
// Run an array of specific seeders...
$this->seed([
OrderStatusSeeder::class,
TransactionStatusSeeder::class,
// ...
]);
}
}
あるいは、RefreshDatabase
トレイトを使用する各 test の前に Laravel に自動的に seed を database に行うよう指示することもできます。これは、ベース test class 上に $seed
プロパティを定義することで実現できます:
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
/**
* Indicates whether the default seeder should run before each test.
*
* @var bool
*/
protected $seed = true;
}
$seed
プロパティがtrue
の場合、test はRefreshDatabase
トレイトを使用する各 test の前にDatabase\Seeders\DatabaseSeeder
class を実行します。ただし、test class 上の$seeder
プロパティを定義することで実行するべき特定のシーダーを指定することができます。
use Database\Seeders\OrderStatusSeeder;
/**
* Run a specific seeder before each test.
*
* @var string
*/
protected $seeder = OrderStatusSeeder::class;
Available Assertions
Laravel は、Pest またはPHPUnit の feature test のためのいくつかの database アサーションを提供します。以下でこれらのアサーションのそれぞれについて議論します。
assertDatabaseCount
database のテーブルに指定された数のレコードが含まれていることを Assert します:
$this->assertDatabaseCount('users', 5);
assertDatabaseHas
指定されたキー/ value query 制約に一致するレコードを database のテーブルが含んでいると Assert します:
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);
assertDatabaseMissing
database 内のテーブルが与えられた key/ value query 制約に一致するレコードを含まないことを Assert します:
$this->assertDatabaseMissing('users', [
'email' => 'sally@example.com',
]);
assertSoftDeleted
assertSoftDeleted
method は、特定の Eloquent model が "soft deleted"されたことを assert するために使用できます。
$this->assertSoftDeleted($user);
assertNotSoftDeleted
assertNotSoftDeleted
method は、特定の Eloquent model が "soft deleted" されていないことを assert するために使用できます。
$this->assertNotSoftDeleted($user);
assertModelExists
指定された model が database に存在することを Assert します:
use App\Models\User;
$user = User::factory()->create();
$this->assertModelExists($user);
assertModelMissing
指定された model が database に存在しないと Assert します:
use App\Models\User;
$user = User::factory()->create();
$user->delete();
$this->assertModelMissing($user);
expectsDatabaseQueryCount
test の開始時に、test 中に実行されることを予期する databasequeries の合計数を指定するために、expectsDatabaseQueryCount
method を呼び出すことができます。実際に実行された queries の数がこの期待 values と一致しない場合、test は失敗します。
$this->expectsDatabaseQueryCount(5);
// Test...