Skip to content
全部文档

数据库测试

简介

Laravel 提供多种实用工具与断言,让你更容易测试依赖数据库的应用。此外,Laravel 模型工厂与填充器可轻松使用应用的 Eloquent 模型与关联创建测试数据库记录。下文将讨论这些强大功能。

每次测试后重置数据库

在继续深入之前,我们先讨论如何在每次测试后重置数据库,以免前一次测试的数据干扰后续测试。Laravel 自带的 Illuminate\Foundation\Testing\RefreshDatabase trait 会帮你处理此事。只需在测试类上使用该 trait:

php
<?php

use Illuminate\Foundation\Testing\RefreshDatabase;

pest()->use(RefreshDatabase::class);

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

    // ...
});
php
<?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 trait 不会迁移数据库,而只会在数据库事务中执行测试。因此,未使用该 trait 的测试用例写入数据库的记录仍可能留在库中。

若要彻底重置数据库,可改用 Illuminate\Foundation\Testing\DatabaseMigrationsIlluminate\Foundation\Testing\DatabaseTruncation trait。不过这两种方式都比 RefreshDatabase trait 慢得多。

模型工厂

测试时,你可能需要在执行测试前向数据库插入若干记录。与其在创建测试数据时手动指定每列的值,Laravel 允许你使用模型工厂为每个 Eloquent 模型定义一组默认属性。

要进一步了解如何创建并使用模型工厂来生成模型,请参阅完整的模型工厂文档。定义好模型工厂后,即可在测试中使用该工厂创建模型:

php
use App\Models\User;

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

    // ...
});
php
use App\Models\User;

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

    // ...
}

运行填充器

若要在功能测试期间使用数据库填充器填充数据库,可调用 seed 方法。默认情况下,seed 方法会执行 DatabaseSeeder,而后者应执行你所有其他填充器。或者,你也可以向 seed 方法传入特定填充器类名:

php
<?php

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

pest()->use(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
<?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,
            // ...
        ]);
    }
}

或者,你可以让 Laravel 在每个使用 RefreshDatabase trait 的测试之前自动填充数据库。方法是在基础测试类上定义 $seed 属性:

php
<?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 时,在每个使用 RefreshDatabase trait 的测试之前会运行 Database\Seeders\DatabaseSeeder 类。不过,你也可以在测试类上定义 $seeder 属性,以指定应执行的特定填充器:

php
use Database\Seeders\OrderStatusSeeder;

/**
 * Run a specific seeder before each test.
 *
 * @var string
 */
protected $seeder = OrderStatusSeeder::class;

可用断言

Laravel 为 PestPHPUnit 功能测试提供若干数据库断言。下文将逐一说明。

assertDatabaseCount

断言数据库中的某张表包含给定数量的记录:

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

assertDatabaseEmpty

断言数据库中的某张表不包含任何记录:

php
$this->assertDatabaseEmpty('users');

assertDatabaseHas

断言数据库中的某张表包含符合给定键 / 值查询约束的记录:

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

assertDatabaseMissing

断言数据库中的某张表不包含符合给定键 / 值查询约束的记录:

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

assertSoftDeleted

assertSoftDeleted 方法可用于断言给定 Eloquent 模型已被「软删除」:

php
$this->assertSoftDeleted($user);

assertNotSoftDeleted

assertNotSoftDeleted 方法可用于断言给定 Eloquent 模型尚未被「软删除」:

php
$this->assertNotSoftDeleted($user);

assertModelExists

断言给定模型或模型集合存在于数据库中:

php
use App\Models\User;

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

$this->assertModelExists($user);

assertModelMissing

断言给定模型或模型集合不存在于数据库中:

php
use App\Models\User;

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

$user->delete();

$this->assertModelMissing($user);

expectsDatabaseQueryCount

可在测试开头调用 expectsDatabaseQueryCount 方法,指定测试期间期望执行的数据库查询总数。若实际执行的查询数与期望不完全一致,测试将失败:

php
$this->expectsDatabaseQueryCount(5);

// Test...