跳至内容

数据库测试

简介

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

每次测试后重置数据库

在继续之前,让我们讨论如何在每次测试后重置数据库,以便先前测试中的数据不会干扰后续测试。Laravel 内置的 `Illuminate\Foundation\Testing\RefreshDatabase` 特性将为您处理此问题。只需在您的测试类上使用此特性即可

<?php
 
use Illuminate\Foundation\Testing\RefreshDatabase;
 
uses(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;
 
/**
* A basic functional test example.
*/
public function test_basic_example(): void
{
$response = $this->get('/');
 
// ...
}
}

如果您的模式是最新的,则 `Illuminate\Foundation\Testing\RefreshDatabase` 特性不会迁移您的数据库。相反,它只会在一个数据库事务中执行测试。因此,未使用此特性的测试用例添加到数据库中的任何记录可能仍存在于数据库中。

如果您希望完全重置数据库,可以使用 `Illuminate\Foundation\Testing\DatabaseMigrations` 或 `Illuminate\Foundation\Testing\DatabaseTruncation` 特性。但是,这两个选项都比 `RefreshDatabase` 特性慢得多。

模型工厂

在测试期间,您可能需要在执行测试之前将一些记录插入数据库。与其在创建这些测试数据时手动指定每个列的值,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();
 
// ...
}

运行播种器

如果您想在功能测试期间使用 数据库播种器 来填充您的数据库,您可以调用 `seed` 方法。默认情况下,`seed` 方法将执行 `DatabaseSeeder`,它应该执行您所有其他播种器。或者,您可以将特定的播种器类名称传递给 `seed` 方法

<?php
 
use Database\Seeders\OrderStatusSeeder;
use Database\Seeders\TransactionStatusSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
 
uses(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
 
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` 特性的测试之前自动播种数据库。您可以通过在基本测试类上定义 `$seed` 属性来实现这一点

<?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` 特性的测试之前运行 `Database\Seeders\DatabaseSeeder` 类。但是,您可以通过在测试类上定义 `$seeder` 属性来指定要执行的特定播种器

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

可用的断言

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

assertDatabaseCount

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

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

assertDatabaseHas

断言数据库中的表包含与给定的键/值查询约束匹配的记录

$this->assertDatabaseHas('users', [
'email' => '[email protected]',
]);

assertDatabaseMissing

断言数据库中的表不包含与给定的键/值查询约束匹配的记录

$this->assertDatabaseMissing('users', [
'email' => '[email protected]',
]);

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);
 
// Test...