Introduction
Laravel provides a variety of helpful tools and assertions to make it easier to test your database driven applications. In addition, Laravel model factories and seeders make it painless to create test database records using your application's Eloquent models and relationships. We'll discuss all of these powerful features in the following documentation.
Resetting the Database After Each Test
Before proceeding much further, let's discuss how to
reset your database after each of your tests so that
data from a previous test does not interfere with
subsequent tests. Laravel's included
Illuminate\Foundation\Testing\RefreshDatabase
trait will take care of this for you. Simply use the
trait on your test class:
<?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('/');
// ...
}
}
The
Illuminate\Foundation\Testing\RefreshDatabase
trait does not migrate your database if your schema is
up to date. Instead, it will only execute the test
within a database transaction. Therefore, any records
added to the database by test cases that do not use this
trait may still exist in the database.
If you would like to totally reset the database, you may
use the
Illuminate\Foundation\Testing\DatabaseMigrations
or
Illuminate\Foundation\Testing\DatabaseTruncation
traits instead. However, both of these options are
significantly slower than the
RefreshDatabase
trait.
Model Factories
When testing, you may need to insert a few records into your database before executing your test. Instead of manually specifying the value of each column when you create this test data, Laravel allows you to define a set of default attributes for each of your Eloquent models using model factories.
To learn more about creating and utilizing model factories to create models, please consult the complete model factory documentation. Once you have defined a model factory, you may utilize the factory within your test to create models:
use App\Models\User;
public function test_models_can_be_instantiated(): void
{
$user = User::factory()->create();
// ...
}
Running Seeders
If you would like to use database
seeders to populate your database during a
feature test, you may invoke the seed
method. By default, the seed
method will
execute the DatabaseSeeder
, which should
execute all of your other seeders. Alternatively, you
pass a specific seeder class name to the
seed
method:
<?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,
// ...
]);
}
}
Alternatively, you may instruct Laravel to automatically
seed the database before each test that uses the
RefreshDatabase
trait. You may accomplish
this by defining a $seed
property on your
base test class:
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
/**
* Indicates whether the default seeder should run before each test.
*
* @var bool
*/
protected $seed = true;
}
When the $seed
property is
true
, the test will run the
Database\Seeders\DatabaseSeeder
class
before each test that uses the
RefreshDatabase
trait. However, you may
specify a specific seeder that should be executed by
defining a $seeder
property on your test
class:
use Database\Seeders\OrderStatusSeeder;
/**
* Run a specific seeder before each test.
*
* @var string
*/
protected $seeder = OrderStatusSeeder::class;
Available Assertions
Laravel provides several database assertions for your PHPUnit feature tests. We'll discuss each of these assertions below.
assertDatabaseCount
Assert that a table in the database contains the given number of records:
$this->assertDatabaseCount('users', 5);
assertDatabaseHas
Assert that a table in the database contains records matching the given key / value query constraints:
$this->assertDatabaseHas('users', [
'email' => 'sally@example.com',
]);
assertDatabaseMissing
Assert that a table in the database does not contain records matching the given key / value query constraints:
$this->assertDatabaseMissing('users', [
'email' => 'sally@example.com',
]);
assertSoftDeleted
The assertSoftDeleted
method may be used to
assert a given Eloquent model has been "soft
deleted":
$this->assertSoftDeleted($user);
assertNotSoftDeleted
The assertNotSoftDeleted
method may be used
to assert a given Eloquent model hasn't been "soft
deleted":
$this->assertNotSoftDeleted($user);
assertModelExists
Assert that a given model exists in the database:
use App\Models\User;
$user = User::factory()->create();
$this->assertModelExists($user);
assertModelMissing
Assert that a given model does not exist in the database:
use App\Models\User;
$user = User::factory()->create();
$user->delete();
$this->assertModelMissing($user);
expectsDatabaseQueryCount
The expectsDatabaseQueryCount
method may be
invoked at the beginning of your test to specify the
total number of database queries that you expect to be
run during the test. If the actual number of executed
queries does not exactly match this expectation, the
test will fail:
$this->expectsDatabaseQueryCount(5);
// Test...