Skip to main content

Introduction

Laravel provides first-class support for testing database-driven applications. You can combine database reset traits, model factories, and test-specific assertions to write fast and reliable feature tests. In most cases, start with RefreshDatabase. It keeps tests isolated while remaining faster than fully rebuilding the database every time.

Resetting the database after each test

To prevent data from one test affecting another test, use one of Laravel’s database reset traits.
<?php

use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('basic example', function () {
    $response = $this->get('/');

    $response->assertOk();
});
<?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('/');

        $response->assertOk();
    }
}
RefreshDatabase checks whether the database schema is already up to date. If it is, Laravel runs each test in a transaction. If it is not, Laravel runs migrations first. If you need a full reset strategy instead of transaction-based isolation, use the following traits:
TraitBehaviorWhen to use
RefreshDatabaseUses transactions if schema is current; migrates when neededDefault choice for most test suites
DatabaseMigrationsRuns migrations for each testWhen you need migration-level lifecycle behavior in every test
DatabaseTruncationTruncates tables between testsWhen transactions are not suitable and truncation fits your DB workflow

Model factories

Before asserting behavior, you often need test data. Laravel model factories provide expressive defaults for creating Eloquent models. For full factory definitions and advanced states / relationships, see Eloquent Factories.
<?php

use App\Models\User;

test('models can be instantiated', function () {
    $user = User::factory()->create();

    expect($user->exists)->toBeTrue();
});
<?php

namespace Tests\Feature;

use App\Models\User;
use Tests\TestCase;

class UserFactoryTest extends TestCase
{
    public function test_models_can_be_instantiated(): void
    {
        $user = User::factory()->create();

        $this->assertTrue($user->exists);
    }
}

Running seeders

Use the seed() method to populate data during tests. Without arguments, it runs DatabaseSeeder. You can also run a specific seeder class or an array of classes.
<?php

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

uses(RefreshDatabase::class);

test('orders can be created', function () {
    $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 OrderTest extends TestCase
{
    use RefreshDatabase;

    public function test_orders_can_be_created(): void
    {
        $this->seed();

        $this->seed(OrderStatusSeeder::class);

        $this->seed([
            OrderStatusSeeder::class,
            TransactionStatusSeeder::class,
        ]);

        // ...
    }
}
You may also seed automatically for tests using RefreshDatabase by using attributes:
<?php

namespace Tests;

use Illuminate\Foundation\Testing\Attributes\Seed;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;

#[Seed]
abstract class TestCase extends BaseTestCase
{
}
To run a specific seeder automatically, use #[Seeder(...)]:
<?php

namespace Tests\Feature;

use Database\Seeders\OrderStatusSeeder;
use Illuminate\Foundation\Testing\Attributes\Seeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

#[Seeder(OrderStatusSeeder::class)]
class OrderStatusTest extends TestCase
{
    use RefreshDatabase;
}

Available assertions

Laravel provides dedicated database assertions for both Pest and PHPUnit feature tests.

assertDatabaseCount

Assert that a table contains the expected number of records.
$this->assertDatabaseCount('users', 5);
$this->assertDatabaseCount('users', 5);

assertDatabaseEmpty

Assert that a table contains no records.
$this->assertDatabaseEmpty('users');
$this->assertDatabaseEmpty('users');

assertDatabaseHas

Assert that a table contains records matching the given attributes.
$this->assertDatabaseHas('users', [
    'email' => '[email protected]',
]);
$this->assertDatabaseHas('users', [
    'email' => '[email protected]',
]);

assertDatabaseMissing

Assert that a table does not contain records matching the given attributes.
$this->assertDatabaseMissing('users', [
    'email' => '[email protected]',
]);
$this->assertDatabaseMissing('users', [
    'email' => '[email protected]',
]);

assertSoftDeleted

Assert that the given model has been soft deleted.
$this->assertSoftDeleted($user);
$this->assertSoftDeleted($user);

assertNotSoftDeleted

Assert that the given model has not been soft deleted.
$this->assertNotSoftDeleted($user);
$this->assertNotSoftDeleted($user);

assertModelExists

Assert that the given model (or collection of models) exists in the database.
<?php

use App\Models\User;

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

$this->assertModelExists($user);
<?php

use App\Models\User;

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

$this->assertModelExists($user);

assertModelMissing

Assert that the given model (or collection of models) does not exist in the database.
<?php

use App\Models\User;

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

$this->assertModelMissing($user);
<?php

use App\Models\User;

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

$this->assertModelMissing($user);

expectsDatabaseQueryCount

Call this at the beginning of a test to assert the exact total number of database queries executed.
$this->expectsDatabaseQueryCount(5);

// Test...
$this->expectsDatabaseQueryCount(5);

// Test...
Last modified on May 29, 2026