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;

    /**
     * 一个基本的功能测试示例。
     */
    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 () {
    // 运行 DatabaseSeeder...
    $this->seed();

    // 运行特定的数据填充器...
    $this->seed(OrderStatusSeeder::class);

    // ...

    // 运行一组特定的数据填充器...
    $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;

    /**
     * 测试创建新订单。
     */
    public function test_orders_can_be_created(): void
    {
        // 运行 DatabaseSeeder...
        $this->seed();

        // 运行特定的数据填充器...
        $this->seed(OrderStatusSeeder::class);

        // ...

        // 运行一组特定的数据填充器...
        $this->seed([
            OrderStatusSeeder::class,
            TransactionStatusSeeder::class,
            // ...
        ]);
    }
}

或者,你可以指示 Laravel 在每个使用 RefreshDatabase trait 的测试之前自动填充数据库。你可以通过向基础测试类添加 Seed 属性来实现这一点:

php
<?php

namespace Tests;

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

#[Seed]
abstract class TestCase extends BaseTestCase
{
}

当存在 Seed 属性时,测试将在每个使用 RefreshDatabase trait 的测试之前运行 Database\Seeders\DatabaseSeeder 类。但是,你可以通过在测试类上使用 Seeder 属性来指定应该执行的特定数据填充器:

php
<?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 OrderTest extends TestCase
{
    use RefreshDatabase;

    // ...
}

可用断言

Laravel 为你的 PestPHPUnit 功能测试提供了多个数据库断言。我们将在下面讨论每个断言。