跳轉至內容

資料庫測試

簡介

Laravel 提供了多種實用的工具和斷言,使測試資料庫驅動的應用程式變得更加容易。此外,Laravel 的模型工廠(Model Factories)和資料填充器(Seeders)可以讓你使用應用程式的 Eloquent 模型和關聯關係輕鬆建立測試資料庫記錄。我們將在本文件中討論所有這些強大的功能。

在每次測試後重置資料庫

在繼續深入之前,讓我們先討論如何在每次測試後重置資料庫,以確保上一次測試的資料不會干擾後續測試。Laravel 內建的 Illuminate\Foundation\Testing\RefreshDatabase trait 會為你處理好這一切。只需在你的測試類中使用該 trait 即可。

1<?php
2 
3use Illuminate\Foundation\Testing\RefreshDatabase;
4 
5pest()->use(RefreshDatabase::class);
6 
7test('basic example', function () {
8 $response = $this->get('/');
9 
10 // ...
11});
1<?php
2 
3namespace Tests\Feature;
4 
5use Illuminate\Foundation\Testing\RefreshDatabase;
6use Tests\TestCase;
7 
8class ExampleTest extends TestCase
9{
10 use RefreshDatabase;
11 
12 /**
13 * A basic functional test example.
14 */
15 public function test_basic_example(): void
16 {
17 $response = $this->get('/');
18 
19 // ...
20 }
21}

如果你的架構(Schema)已是最新,Illuminate\Foundation\Testing\RefreshDatabase trait 不會重新遷移資料庫。相反,它僅會在資料庫事務內執行測試。因此,未顯式使用此 trait 的測試用例所新增的記錄可能會殘留於資料庫中。

如果你希望徹底重置資料庫,可以使用 Illuminate\Foundation\Testing\DatabaseMigrationsIlluminate\Foundation\Testing\DatabaseTruncation trait 代替。不過,這兩種方案的執行速度都比 RefreshDatabase trait 慢得多。

模型工廠

在進行測試時,你可能需要在執行測試前向資料庫插入幾條記錄。與其在建立測試資料時手動指定每一列的值,Laravel 允許你使用 模型工廠 為你的 Eloquent 模型 定義一組預設屬性。

要了解有關建立和利用模型工廠來生成模型的更多資訊,請參閱完整的 模型工廠文件。一旦定義了模型工廠,你就可以在測試中使用該工廠來建立模型。

1use App\Models\User;
2 
3test('models can be instantiated', function () {
4 $user = User::factory()->create();
5 
6 // ...
7});
1use App\Models\User;
2 
3public function test_models_can_be_instantiated(): void
4{
5 $user = User::factory()->create();
6 
7 // ...
8}

執行資料填充器

如果你希望在功能測試期間使用 資料庫填充器 來填充資料庫,可以呼叫 seed 方法。預設情況下,seed 方法會執行 DatabaseSeeder,該類應包含你所有其他填充器的執行邏輯。或者,你也可以將特定的填充器類名傳遞給 seed 方法。

1<?php
2 
3use Database\Seeders\OrderStatusSeeder;
4use Database\Seeders\TransactionStatusSeeder;
5use Illuminate\Foundation\Testing\RefreshDatabase;
6 
7pest()->use(RefreshDatabase::class);
8 
9test('orders can be created', function () {
10 // Run the DatabaseSeeder...
11 $this->seed();
12 
13 // Run a specific seeder...
14 $this->seed(OrderStatusSeeder::class);
15 
16 // ...
17 
18 // Run an array of specific seeders...
19 $this->seed([
20 OrderStatusSeeder::class,
21 TransactionStatusSeeder::class,
22 // ...
23 ]);
24});
1<?php
2 
3namespace Tests\Feature;
4 
5use Database\Seeders\OrderStatusSeeder;
6use Database\Seeders\TransactionStatusSeeder;
7use Illuminate\Foundation\Testing\RefreshDatabase;
8use Tests\TestCase;
9 
10class ExampleTest extends TestCase
11{
12 use RefreshDatabase;
13 
14 /**
15 * Test creating a new order.
16 */
17 public function test_orders_can_be_created(): void
18 {
19 // Run the DatabaseSeeder...
20 $this->seed();
21 
22 // Run a specific seeder...
23 $this->seed(OrderStatusSeeder::class);
24 
25 // ...
26 
27 // Run an array of specific seeders...
28 $this->seed([
29 OrderStatusSeeder::class,
30 TransactionStatusSeeder::class,
31 // ...
32 ]);
33 }
34}

或者,你也可以指示 Laravel 在每個使用 RefreshDatabase trait 的測試之前自動填充資料庫。透過在你的基礎測試類上新增 Seed 屬性即可實現這一點。

1<?php
2 
3namespace Tests;
4 
5use Illuminate\Foundation\Testing\Attributes\Seed;
6use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
7 
8#[Seed]
9abstract class TestCase extends BaseTestCase
10{
11}

Seed 屬性存在時,測試會在每個使用 RefreshDatabase trait 的測試之前執行 Database\Seeders\DatabaseSeeder 類。此外,你也可以透過在測試類上使用 Seeder 屬性來指定需要執行的特定填充器。

1<?php
2 
3namespace Tests\Feature;
4 
5use Database\Seeders\OrderStatusSeeder;
6use Illuminate\Foundation\Testing\Attributes\Seeder;
7use Illuminate\Foundation\Testing\RefreshDatabase;
8use Tests\TestCase;
9 
10#[Seeder(OrderStatusSeeder::class)]
11class OrderTest extends TestCase
12{
13 use RefreshDatabase;
14 
15 // ...
16}

可用斷言

Laravel 為你的 PestPHPUnit 功能測試提供了多種資料庫斷言。我們將在下面討論這些斷言。

assertDatabaseCount

斷言資料庫中的某個表包含給定數量的記錄。

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

assertDatabaseEmpty

斷言資料庫中的某個表不包含任何記錄。

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

assertDatabaseHas

斷言資料庫中的某個表包含匹配給定鍵/值查詢約束的記錄。

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

assertDatabaseMissing

斷言資料庫中的某個表不包含匹配給定鍵/值查詢約束的記錄。

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

assertSoftDeleted

assertSoftDeleted 方法可用於斷言給定的 Eloquent 模型已被“軟刪除”。

1$this->assertSoftDeleted($user);

assertNotSoftDeleted

assertNotSoftDeleted 方法可用於斷言給定的 Eloquent 模型未被“軟刪除”。

1$this->assertNotSoftDeleted($user);

assertModelExists

斷言給定的模型或模型集合存在於資料庫中。

1use App\Models\User;
2 
3$user = User::factory()->create();
4 
5$this->assertModelExists($user);

assertModelMissing

斷言給定的模型或模型集合不存在於資料庫中。

1use App\Models\User;
2 
3$user = User::factory()->create();
4 
5$user->delete();
6 
7$this->assertModelMissing($user);

expectsDatabaseQueryCount

可以在測試開始時呼叫 expectsDatabaseQueryCount 方法,以指定測試期間預期的資料庫查詢總數。如果實際執行的查詢數量與此預期不完全匹配,測試將會失敗。

1$this->expectsDatabaseQueryCount(5);
2 
3// Test...