Skip to content

データベーステスト

イントロダクション

Laravelは、データベース駆動のアプリケーションを簡単にテストできるように、さまざまな便利なツールとアサーションを提供しています。さらに、Laravelのモデルファクトリとシーダーを使用すると、アプリケーションのEloquentモデルとリレーションを使用して、テストデータベースレコードを簡単に作成できます。これらの強力な機能については、以下のドキュメントで説明します。

各テスト後のデータベースリセット

さらに進む前に、各テスト後にデータベースをリセットする方法について説明しましょう。これにより、前のテストのデータが後続のテストに干渉しないようになります。Laravelに含まれるIlluminate\Foundation\Testing\RefreshDatabaseトレイトが、これを処理します。テストクラスでトレイトを使用するだけです:

<?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;

    /**
     * 基本的な機能テストの例。
     */
    public function test_basic_example(): void
    {
        $response = $this->get('/');

        // ...
    }
}

Illuminate\Foundation\Testing\RefreshDatabaseトレイトは、スキーマが最新の場合、データベースをマイグレートしません。代わりに、データベーストランザクション内でテストを実行するだけです。したがって、このトレイトを使用しないテストケースによってデータベースに追加されたレコードは、データベースに残る可能性があります。

データベースを完全にリセットしたい場合は、代わりにIlluminate\Foundation\Testing\DatabaseMigrationsまたはIlluminate\Foundation\Testing\DatabaseTruncationトレイトを使用できます。ただし、これらのオプションはRefreshDatabaseトレイトよりも大幅に遅くなります。

モデルファクトリ

テストを行う際、テストを実行する前にデータベースにいくつかのレコードを挿入する必要があるかもしれません。このテストデータを作成する際に、各列の値を手動で指定する代わりに、Laravelではモデルファクトリを使用して、各Eloquentモデルのデフォルト属性のセットを定義できます。

モデルファクトリの作成と使用方法について詳しくは、完全なモデルファクトリのドキュメントを参照してください。モデルファクトリを定義したら、テスト内でファクトリを使用してモデルを作成できます:

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();

    // ...
}

シーダーの実行

機能テスト中にデータベースシーダーを使用してデータベースをデータで埋めたい場合は、seedメソッドを呼び出すことができます。デフォルトでは、seedメソッドはDatabaseSeederを実行し、これにより他のすべてのシーダーが実行されます。または、特定のシーダークラス名をseedメソッドに渡すこともできます:

<?php

use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('orders can be created', function () {
    // DatabaseSeederを実行...
    $this->seed();

    // 特定のシーダーを実行...
    $this->seed(OrderStatusSeeder::class);

    // ...

    // 特定のシーダーの配列を実行...
    $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;

    /**
     * 新しい注文の作成テスト。
     */
    public function test_orders_can_be_created(): void
    {
        // DatabaseSeederを実行...
        $this->seed();

        // 特定のシーダーを実行...
        $this->seed(OrderStatusSeeder::class);

        // ...

        // 特定のシーダーの配列を実行...
        $this->seed([
            OrderStatusSeeder::class,
            TransactionStatusSeeder::class,
            // ...
        ]);
    }
}

または、RefreshDatabaseトレイトを使用する各テストの前に、Laravelにデータベースを自動的にシードするように指示できます。これは、ベーステストクラスに$seedプロパティを定義することで実現できます:

<?php

namespace Tests;

use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

abstract class TestCase extends BaseTestCase
{
    /**
     * 各テストの前にデフォルトのシーダーを実行するかどうかを示します。
     *
     * @var bool
     */
    protected $seed = true;
}

$seedプロパティがtrueの場合、RefreshDatabaseトレイトを使用する各テストの前にDatabase\Seeders\DatabaseSeederクラスが実行されます。ただし、テストクラスに$seederプロパティを定義することで、特定のシーダーを実行するように指定できます:

use Database\Seeders\OrderStatusSeeder;

/**
 * 各テストの前に実行する特定のシーダー。
 *
 * @var string
 */
protected $seeder = OrderStatusSeeder::class;

利用可能なアサーション

Laravelは、PestまたはPHPUnitの機能テスト用にいくつかのデータベースアサーションを提供しています。以下では、これらの各アサーションについて説明します。

assertDatabaseCount

データベース内のテーブルに指定された数のレコードが含まれていることをアサートします:

$this->assertDatabaseCount('users', 5);

assertDatabaseHas

データベース内のテーブルに、指定されたキー/値のクエリ制約に一致するレコードが含まれていることをアサートします:

$this->assertDatabaseHas('users', [
    'email' => 'sally@example.com',
]);

assertDatabaseMissing

データベース内のテーブルに、指定されたキー/値のクエリ制約に一致するレコードが含まれていないことをアサートします:

$this->assertDatabaseMissing('users', [
    'email' => 'sally@example.com',
]);

assertSoftDeleted

assertSoftDeletedメソッドは、指定されたEloquentモデルが「ソフトデリート」されたことをアサートするために使用できます:

$this->assertSoftDeleted($user);

assertNotSoftDeleted

assertNotSoftDeletedメソッドは、指定されたEloquentモデルが「ソフトデリート」されていないことをアサートするために使用できます:

$this->assertNotSoftDeleted($user);

assertModelExists

指定されたモデルがデータベースに存在することをアサートします:

use App\Models\User;

$user = User::factory()->create();

$this->assertModelExists($user);

assertModelMissing

指定されたモデルがデータベースに存在しないことをアサートします:

use App\Models\User;

$user = User::factory()->create();

$user->delete();

$this->assertModelMissing($user);

expectsDatabaseQueryCount

expectsDatabaseQueryCountメソッドは、テストの開始時に呼び出され、テスト中に実行されるデータベースクエリの総数を指定できます。実際のクエリ数がこの期待値と一致しない場合、テストは失敗します:

$this->expectsDatabaseQueryCount(5);

// テスト...

ユーザーノート