数据库测试

未匹配的标注
本文档最新版为 12.x,旧版本可能放弃维护,推荐阅读最新版!

数据库测试

简介

Laravel 提供了多种实用工具和断言,让你更轻松地测试基于数据库的应用。此外,Laravel 的模型工厂和 Seeder 让你能够方便地利用应用的 Eloquent 模型及其关系创建供测试使用的数据库记录。下文将介绍这些强大的功能。

每次测试后重置数据库

在进一步介绍之前,我们先来讨论如何在每次测试后重置数据库,避免前一次测试的数据干扰后续测试。Laravel 内置的 Illuminate\Foundation\Testing\RefreshDatabase trait 可以为你完成这项工作。只需在测试类中使用该 trait:

<?php

use Illuminate\Foundation\Testing\RefreshDatabase;

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

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

    // ...
});
<?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\DatabaseMigrations 或 Illuminate\Foundation\Testing\DatabaseTruncation trait。不过,这两种方式都明显慢于 RefreshDatabase trait。

模型工厂

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

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

use App\Models\User;

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

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

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

    // ...
}

运行 Seeder

如果你想在功能测试期间使用 数据库 Seeder 填充数据库,可以调用 seed 方法。默认情况下,seed 方法会执行 DatabaseSeeder,该类应当调用你的其他所有 Seeder。你也可以向 seed 方法传入指定的 Seeder 类名:

<?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();

    // 运行指定的 Seeder……
    $this->seed(OrderStatusSeeder::class);

    // ...

    // 运行数组中指定的多个 Seeder……
    $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 ExampleTest extends TestCase
{
    use RefreshDatabase;

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

        // 运行指定的 Seeder……
        $this->seed(OrderStatusSeeder::class);

        // ...

        // 运行数组中指定的多个 Seeder……
        $this->seed([
            OrderStatusSeeder::class,
            TransactionStatusSeeder::class,
            // ...
        ]);
    }
}

你也可以让 Laravel 在每个使用 RefreshDatabase trait 的测试运行之前,自动填充数据库。只需在基础测试类上添加 Seed 特性:

<?php

namespace Tests;

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

#[Seed]
abstract class TestCase extends BaseTestCase
{
}

添加 Seed 特性后,Laravel 会在每个使用 RefreshDatabase trait 的测试运行之前,执行 Database\Seeders\DatabaseSeeder 类。如果你希望运行指定的 Seeder,可以在测试类上使用 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 OrderTest extends TestCase
{
    use RefreshDatabase;

    // ...
}

可用断言

Laravel 为 Pest 或 PHPUnit 功能测试提供了多种数据库断言。下面将逐一介绍这些断言。

assertDatabaseCount

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

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

assertDatabaseEmpty

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

$this->assertDatabaseEmpty('users');

assertDatabaseHas

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

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

assertDatabaseMissing

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

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

assertSoftDeleted

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

$this->assertSoftDeleted($user);

assertNotSoftDeleted

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

$this->assertNotSoftDeleted($user);

assertModelExists

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

use App\Models\User;

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

$this->assertModelExists($user);

assertModelMissing

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

use App\Models\User;

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

$user->delete();

$this->assertModelMissing($user);

expectsDatabaseQueryCount

你可以在测试开始时调用 expectsDatabaseQueryCount 方法,指定测试期间预期执行的数据库查询总数。如果实际执行的查询数量与预期不完全一致,测试就会失败:

$this->expectsDatabaseQueryCount(5);

// 执行测试……

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/laravel/13.x/da...

译文地址:https://learnku.com/docs/laravel/13.x/da...

上一篇 下一篇
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
贡献者:1
讨论数量: 0
发起讨论 只看当前版本


暂无话题~