資料庫測試

簡介

Laravel 提供了數種實用工具與 Assertion (判斷提示) 讓你能更輕鬆地測試由資料庫驅動的網站。此外,通過 Laravel 的 Model Factory 與 Seeder,也能輕鬆地使用專案的 Eloquent Model 與 Eloquent 關聯來測試資料庫。我們會在接下來的說明文件內討論這些強大的工具。

在每個測試後重設資料庫

在進一步繼續之前,我們先來討論如何在每個測試前重設資料庫,這樣一來前一個測試的資料就不會影響到接下來的測試。Laravel 內含了 Illuminate\Foundation\Testing\RefreshDatabase Trait,會處理這樣的重設。只需要在測試類別內 use 這個 Trait 即可:

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}
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 將不會執行資料庫遷移 (Migration),只會在資料庫 Transaction 中執行測試。因此,在未使用該 Trait 中的測試例中,若有新增紀錄,將會保留在資料庫中。

若想完整重設資料庫,請改用 Illuminate\Foundation\Testing\DatabaseMigrationsIlluminate\Foundation\Testing\DatabaseTruncation Trait。不過,這兩種方式都會比 RefreshDatabase Trait 慢很多。

Model Factory

在測試時,我們可能會需要在執行測試前先插入一些資料到資料庫內。比起在建立這個測試資料時手動指定各個欄位的值,在 Laravel 中,我們可以使用 [Model Factory]((/docs/10.x/eloquent-factories) 來為各個 Eloquent Model 定義一系列的預設屬性。

若要瞭解更多有關建立 Model Factory,或是使用 Model Factory 來建立 Model 的資訊,請參考完整的 Model Factory 說明文件。定義好 Model Factory 後,就可以在測試中使用 Factory 來建立 Model:

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

執行 Seeder

若想使用資料庫 Seeder 來在功能測試時修改資料庫,則可以叫用 seed 方法。預設情況下,seed 方法會執行 DatabaseSeeder,該 Seeder 應用來執行所有其他的 Seeder。或者,也可以傳入指定的 Seeder 類別名稱給 seed 方法:

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 // 執行 DatabaseSeeder...
20 $this->seed();
21 
22 // 執行特定的 Seeder...
23 $this->seed(OrderStatusSeeder::class);
24 
25 // ...
26 
27 // 執行一組特定 Seeder 的陣列...
28 $this->seed([
29 OrderStatusSeeder::class,
30 TransactionStatusSeeder::class,
31 // ...
32 ]);
33 }
34}
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 // 執行 DatabaseSeeder...
20 $this->seed();
21 
22 // 執行特定的 Seeder...
23 $this->seed(OrderStatusSeeder::class);
24 
25 // ...
26 
27 // 執行一組特定 Seeder 的陣列...
28 $this->seed([
29 OrderStatusSeeder::class,
30 TransactionStatusSeeder::class,
31 // ...
32 ]);
33 }
34}

或者,也可以使用 RefreshDatabase Trait 來讓 Laravel 在每次測試前都自動執行資料庫 Seed。可以通過在基礎測試類別上定義 $seed 屬性來完成:

1<?php
2 
3namespace Tests;
4 
5use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
6 
7abstract class TestCase extends BaseTestCase
8{
9 use CreatesApplication;
10 
11 /**
12 * Indicates whether the default seeder should run before each test.
13 *
14 * @var bool
15 */
16 protected $seed = true;
17}
1<?php
2 
3namespace Tests;
4 
5use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
6 
7abstract class TestCase extends BaseTestCase
8{
9 use CreatesApplication;
10 
11 /**
12 * Indicates whether the default seeder should run before each test.
13 *
14 * @var bool
15 */
16 protected $seed = true;
17}

$seed 屬性為 true 時,各個使用了 RefreshDatabase Trait 的測試都會在開始前先執行 Database\Seeders\DatabaseSeeder 類別。不過,也可以通過在測試類別內定義 $seeder 屬性來指定要執行的 Seeder。

1use Database\Seeders\OrderStatusSeeder;
2 
3/**
4 * Run a specific seeder before each test.
5 *
6 * @var string
7 */
8protected $seeder = OrderStatusSeeder::class;
1use Database\Seeders\OrderStatusSeeder;
2 
3/**
4 * Run a specific seeder before each test.
5 *
6 * @var string
7 */
8protected $seeder = OrderStatusSeeder::class;

可用的 Assertion

Laravel 為 [PHPUnit] 功能測試提供了多個資料庫 Assertion。我們會在下方討論逐個討論這些 Assertion。

assertDatabaseCount

判斷資料庫中的某個資料表是否包含給定數量的記錄:

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

assertDatabaseHas

判斷資料庫中的某個資料表包含符合給定索引鍵/值查詢條件的記錄:

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

assertDatabaseMissing

判斷資料庫中的某個資料表是否不包含符合給定索引鍵/值查詢條件的記錄:

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

assertSoftDeleted

assertSoftDeleted 方法可用來判斷給定 Eloquent Model 是否已「軟刪除 (Soft Delete)」:

1$this->assertSoftDeleted($user);
1$this->assertSoftDeleted($user);

assertNotSoftDeleted

assertNotSoftDeleted 方法可用來判斷給定 Eloquent Model 是否未被「軟刪除 (Soft Delete)」:

1$this->assertNotSoftDeleted($user);
1$this->assertNotSoftDeleted($user);

assertModelExists

判斷給定 Model 存在資料庫中:

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

assertModelMissing

判斷給定 Model 不存在資料庫中:

1use App\Models\User;
2 
3$user = User::factory()->create();
4 
5$user->delete();
6 
7$this->assertModelMissing($user);
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// 測試...
1$this->expectsDatabaseQueryCount(5);
2 
3// 測試...
翻譯進度
100% 已翻譯
更新時間:
2024年6月30日 上午8:17:00 [世界標準時間]
翻譯人員:
  • cornch
幫我們翻譯此頁

留言

尚無留言

“Laravel” is a Trademark of Taylor Otwell.
The source documentation is released under MIT license. See laravel/docs on GitHub for details.
The translated documentations are released under MIT license. See cornch/laravel-docs-l10n on GitHub for details.