Skip to content

数据库测试

简介

Laravel 提供了多种有用的工具和断言,使得测试数据库驱动的应用程序变得更加容易。此外,Laravel 的模型工厂和数据填充器使得使用应用程序的 Eloquent 模型和关系创建测试数据库记录变得轻而易举。我们将在接下来的文档中讨论所有这些强大的功能。

每次测试后重置数据库

在进一步讨论之前,让我们先谈谈如何在每次测试后重置数据库,以便前一个测试的数据不会干扰后续的测试。Laravel 包含的 Illuminate\Foundation\Testing\RefreshDatabase trait 会为你处理这个问题。只需在测试类中使用这个 trait:

php
<?php

use Illuminate\Foundation\Testing\RefreshDatabase;

uses(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 不会迁移您的数据库。相反,它只会在数据库事务中执行测试。因此,由不使用此特征的测试用例添加到数据库的任何记录可能仍存在于数据库中。

如果要完全重置数据库,可以改用 Illuminate\Foundation\Testing\DatabaseMigrations or Illuminate\Foundation\Testing\DatabaseTruncation 特征。但是,这两个选项都明显慢于 RefreshDatabase 特征。

模型工厂

当测试时,您可能需要在数据库中插入一些记录,然后执行测试。然而,手动指定每个列的值来创建测试数据并不是一个好主意。Laravel 允许您为每个 Eloquent 模型定义一组默认属性,以便在测试中创建测试数据。您可以使用 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;

uses(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 特征的测试之前自动设定数据库种子。您可以通过在基测试类上定义 $seed 属性来实现此目的:

php
    <?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 属性来指定应该执行的特定 seeder:

php
    use Database\Seeders\OrderStatusSeeder;

    /**
     * 每次测试前运行一个特定的播种机
     *
     * @var string
     */
    protected $seeder = OrderStatusSeeder::class;

可用的断言

Laravel 提供了多种数据库断言来帮助您测试您的 PestPHPUnit 功能测试。我们将在下面讨论每个断言。

assertDatabaseCount

断言数据库中某个表包含的记录数量:

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

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...