資料庫測試
簡介
Laravel 提供了數種實用工具與 Assertion (判斷提示) 讓你能更輕鬆地測試由資料庫驅動的網站。此外,通過 Laravel 的 Model Factory 與 Seeder,也能輕鬆地使用專案的 Eloquent Model 與 Eloquent 關聯來測試資料庫。我們會在接下來的說明文件內討論這些強大的工具。
在每個測試後重設資料庫
在進一步繼續之前,我們先來討論如何在每個測試前重設資料庫,這樣一來前一個測試的資料就不會影響到接下來的測試。Laravel 內含了 Illuminate\Foundation\Testing\RefreshDatabase
Trait,會處理這樣的重設。只需要在測試類別內 use 這個 Trait 即可:
1<?php23namespace Tests\Feature;45use Illuminate\Foundation\Testing\RefreshDatabase;6use Illuminate\Foundation\Testing\WithoutMiddleware;7use Tests\TestCase;89class ExampleTest extends TestCase10{11 use RefreshDatabase;1213 /**14 * A basic functional test example.15 *16 * @return void17 */18 public function test_basic_example()19 {20 $response = $this->get('/');2122 // ...23 }24}
1<?php23namespace Tests\Feature;45use Illuminate\Foundation\Testing\RefreshDatabase;6use Illuminate\Foundation\Testing\WithoutMiddleware;7use Tests\TestCase;89class ExampleTest extends TestCase10{11 use RefreshDatabase;1213 /**14 * A basic functional test example.15 *16 * @return void17 */18 public function test_basic_example()19 {20 $response = $this->get('/');2122 // ...23 }24}
定義 Model Factory
概念概覽
首先,來討論有關 Eloquent Model Factory。在測試時,我們可能會需要在執行測試前先插入一些資料到資料庫內。比起在建立這個測試資料時手動指定各個欄位的值,Laravel 中可以使用 Model Factory 來為各個 Eloquent Model 定義一系列的預設屬性。
若要看看如何撰寫 Factory 的範例,請參考專案中的 database/factories/UserFactory.php
。該 Factory 包含在所有的 Laravel 新專案內,裡面有下列 Factory 定義:
1namespace Database\Factories;23use Illuminate\Database\Eloquent\Factories\Factory;4use Illuminate\Support\Str;56class UserFactory extends Factory7{8 /**9 * Define the model's default state.10 *11 * @return array12 */13 public function definition()14 {15 return [16 'name' => $this->faker->name(),17 'email' => $this->faker->unique()->safeEmail(),18 'email_verified_at' => now(),19 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password20 'remember_token' => Str::random(10),21 ];22 }23}
1namespace Database\Factories;23use Illuminate\Database\Eloquent\Factories\Factory;4use Illuminate\Support\Str;56class UserFactory extends Factory7{8 /**9 * Define the model's default state.10 *11 * @return array12 */13 public function definition()14 {15 return [16 'name' => $this->faker->name(),17 'email' => $this->faker->unique()->safeEmail(),18 'email_verified_at' => now(),19 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password20 'remember_token' => Str::random(10),21 ];22 }23}
如上所示,最基礎的 Factory 格式就像這樣,只需繼承 Laravel 的基礎 Factory 類別並定義一個 definition
方法。definition
方法應回傳一組預設的屬性值,會在使用 Factory 建立 Model 時被套用到該 Model 上。
通過 faker
屬性,Factory 就可以存取 Faker PHP 函式庫。該函式庫可用來方便地產生各種類型的隨機資料以進行測試。
You can set your application's Faker locale by adding a faker_locale
option to your config/app.php
configuration file.
產生 Factory
若要建立 Factory,請執行 make:factory
Artisan 指令:
1php artisan make:factory PostFactory
1php artisan make:factory PostFactory
新的 Factory 類別會被放在 database/factories
目錄內。
Model 於 Factory 的自動偵測慣例
定義好 Factory 後,就可以使用 Illuminate\Database\Eloquent\Factories\HasFactory
Trait 提供給 Model 的靜態 factory
方法來為該 Model 初始化一個 Factory 實體。
HasFactory
Trait 的 factory
方法會使用慣例來判斷適合用於該 Model 的 Factory。更準確來講,該方法會在 Database\Factories
命名空間下尋找符合該 Model 名稱並以 Factory
結尾的類別。若這些慣例不適合用在你正在寫的專案或 Factory,則可以在 Model 上複寫 newFactory
方法來直接回傳與該 Model 對應的 Factory 實體:
1use Database\Factories\Administration\FlightFactory;23/**4 * Create a new factory instance for the model.5 *6 * @return \Illuminate\Database\Eloquent\Factories\Factory7 */8protected static function newFactory()9{10 return FlightFactory::new();11}
1use Database\Factories\Administration\FlightFactory;23/**4 * Create a new factory instance for the model.5 *6 * @return \Illuminate\Database\Eloquent\Factories\Factory7 */8protected static function newFactory()9{10 return FlightFactory::new();11}
接著,在對應的 Factory 上定義一個 model
屬性:
1use App\Administration\Flight;2use Illuminate\Database\Eloquent\Factories\Factory;34class FlightFactory extends Factory5{6 /**7 * The name of the factory's corresponding model.8 *9 * @var string10 */11 protected $model = Flight::class;12}
1use App\Administration\Flight;2use Illuminate\Database\Eloquent\Factories\Factory;34class FlightFactory extends Factory5{6 /**7 * The name of the factory's corresponding model.8 *9 * @var string10 */11 protected $model = Flight::class;12}
Factory State
State 操作方法可定義一些個別的修改,並可任意組合套用到 Model Factory 上。舉例來說,Database\Factories\UserFactory
Factory 可包含一個 suspended
(已停用) State 方法,用來修改該 Model Factory 的預設屬性值。
State 變換方法通常是呼叫 Laravel 基礎 Factory 類別所提供的 state
方法。這個 state
方法接受一個閉包,該閉包會收到一組陣列,陣列內包含了由這個 Factory 所定義的原始屬性。該閉包應回傳一組陣列,期中包含要修改的屬性:
1/**2 * Indicate that the user is suspended.3 *4 * @return \Illuminate\Database\Eloquent\Factories\Factory5 */6public function suspended()7{8 return $this->state(function (array $attributes) {9 return [10 'account_status' => 'suspended',11 ];12 });13}
1/**2 * Indicate that the user is suspended.3 *4 * @return \Illuminate\Database\Eloquent\Factories\Factory5 */6public function suspended()7{8 return $this->state(function (array $attributes) {9 return [10 'account_status' => 'suspended',11 ];12 });13}
Factory 回呼
Factory 回呼使用 afterMaking
與 afterCreating
方法來註冊,能讓你在產生或建立 Model 時執行額外的任務。要註冊這些回呼,應在 Factory 類別上定義一個 configure
方法。Laravel 會在 Factory 初始化後自動呼叫這個方法:
1namespace Database\Factories;23use App\Models\User;4use Illuminate\Database\Eloquent\Factories\Factory;5use Illuminate\Support\Str;67class UserFactory extends Factory8{9 /**10 * Configure the model factory.11 *12 * @return $this13 */14 public function configure()15 {16 return $this->afterMaking(function (User $user) {17 //18 })->afterCreating(function (User $user) {19 //20 });21 }2223 // ...24}
1namespace Database\Factories;23use App\Models\User;4use Illuminate\Database\Eloquent\Factories\Factory;5use Illuminate\Support\Str;67class UserFactory extends Factory8{9 /**10 * Configure the model factory.11 *12 * @return $this13 */14 public function configure()15 {16 return $this->afterMaking(function (User $user) {17 //18 })->afterCreating(function (User $user) {19 //20 });21 }2223 // ...24}
使用 Factory 來建立 Model
產生 Model
定義好 Factory 後,就可以使用 Illuminate\Database\Eloquent\Factories\HasFactory
trait 提供給 Model 的 factory
靜態方法來產生用於該 Model 的 Factory 實體。來看看一些建立 Model 的範例。首先,我們先使用 make
方法來在不儲存進資料庫的情況下建立 Model:
1use App\Models\User;23public function test_models_can_be_instantiated()4{5 $user = User::factory()->make();67 // Use model in tests...8}
1use App\Models\User;23public function test_models_can_be_instantiated()4{5 $user = User::factory()->make();67 // Use model in tests...8}
可以使用 count
方法來建立包含多個 Model 的 Collection:
1$users = User::factory()->count(3)->make();
1$users = User::factory()->count(3)->make();
套用 State
也可以將 State 套用至 Model 上。若想套用多個 State 變換到 Model 上,只需要直接呼叫 State 變換方法即可:
1$users = User::factory()->count(5)->suspended()->make();
1$users = User::factory()->count(5)->suspended()->make();
複寫屬性
若想複寫 Model 上的一些預設值,可以傳入陣列到 make
方法上。只要指定要取代的屬性即可,剩下的屬性會保持 Factory 所指定的預設值:
1$user = User::factory()->make([2 'name' => 'Abigail Otwell',3]);
1$user = User::factory()->make([2 'name' => 'Abigail Otwell',3]);
或者,也可以直接在 Factory 實體上呼叫 state
方法來內嵌 State 變換:
1$user = User::factory()->state([2 'name' => 'Abigail Otwell',3])->make();
1$user = User::factory()->state([2 'name' => 'Abigail Otwell',3])->make();
Mass assignment protection is automatically disabled when creating models using factories.
持續性 Model
create
方法會產生 Model 實體並使用 Eloquent 的 save
方法來將其永久保存於資料庫內:
1use App\Models\User;23public function test_models_can_be_persisted()4{5 // Create a single App\Models\User instance...6 $user = User::factory()->create();78 // Create three App\Models\User instances...9 $users = User::factory()->count(3)->create();1011 // Use model in tests...12}
1use App\Models\User;23public function test_models_can_be_persisted()4{5 // Create a single App\Models\User instance...6 $user = User::factory()->create();78 // Create three App\Models\User instances...9 $users = User::factory()->count(3)->create();1011 // Use model in tests...12}
可以通過將一組屬性陣列傳入 create
方法來複寫該 Factory 的預設 Model 屬性:
1$user = User::factory()->create([2 'name' => 'Abigail',3]);
1$user = User::factory()->create([2 'name' => 'Abigail',3]);
Sequence (序列)
有時候,我們可能會需要為每個建立的 Model 更改某個特定的屬性。可以通過將 State 變換定義為序列來達成。舉例來說,我們可能會想為每個建立的使用者設定 admin
欄位的值為 Y
或 N
:
1use App\Models\User;2use Illuminate\Database\Eloquent\Factories\Sequence;34$users = User::factory()5 ->count(10)6 ->state(new Sequence(7 ['admin' => 'Y'],8 ['admin' => 'N'],9 ))10 ->create();
1use App\Models\User;2use Illuminate\Database\Eloquent\Factories\Sequence;34$users = User::factory()5 ->count(10)6 ->state(new Sequence(7 ['admin' => 'Y'],8 ['admin' => 'N'],9 ))10 ->create();
在上面的範例中,有五個使用者會以 admin
值 Y
建立,另外五個使用者將以 admin
值 N
建立。
若有需要,也可以提供閉包作為序列的值。該閉包會在每次序列需要新值是被叫用:
1$users = User::factory()2 ->count(10)3 ->state(new Sequence(4 fn ($sequence) => ['role' => UserRoles::all()->random()],5 ))6 ->create();
1$users = User::factory()2 ->count(10)3 ->state(new Sequence(4 fn ($sequence) => ['role' => UserRoles::all()->random()],5 ))6 ->create();
在 Sequence 閉包中,可以在注入到閉包中的 Sequence 實體上存取 $index
與 $count
屬性。$index
屬性包含了該 Sequence 到目前為止所進行的迭代數,而 $count
屬性則代表了該 Sequence 總過將被叫用幾次:
1$users = User::factory()2 ->count(10)3 ->sequence(fn ($sequence) => ['name' => 'Name '.$sequence->index])4 ->create();
1$users = User::factory()2 ->count(10)3 ->sequence(fn ($sequence) => ['name' => 'Name '.$sequence->index])4 ->create();
Factory 關聯
Has Many 關聯
接著,來看看如何使用 Laravel 中流利的 Factory 方法建立 Eloquent Model 關聯。首先,假設專案中有個 App\Models\User
Model 以及 App\Models\Post
Model。然後,假設 User
Model 中定義了對 Post
的 hasMany
關聯。我們可以使用 Laravel Factory 提供的 has
方法來建立一個有三篇貼文的使用者。這個 has
方法接受一個 Factory 實體:
1use App\Models\Post;2use App\Models\User;34$user = User::factory()5 ->has(Post::factory()->count(3))6 ->create();
1use App\Models\Post;2use App\Models\User;34$user = User::factory()5 ->has(Post::factory()->count(3))6 ->create();
依照慣例,當傳入 Post
Model 給 has
方法時,Laravel 會假設 User
Model 中有定義這個關聯的 posts
方法。若有需要,可以明顯指定要操作的關聯名稱:
1$user = User::factory()2 ->has(Post::factory()->count(3), 'posts')3 ->create();
1$user = User::factory()2 ->has(Post::factory()->count(3), 'posts')3 ->create();
當然,也可以在關聯 Model 上進行 State 操作。此外,若 State 更改需要存取上層 Model,也可以傳入基於閉包的 State 變換:
1$user = User::factory()2 ->has(3 Post::factory()4 ->count(3)5 ->state(function (array $attributes, User $user) {6 return ['user_type' => $user->type];7 })8 )9 ->create();
1$user = User::factory()2 ->has(3 Post::factory()4 ->count(3)5 ->state(function (array $attributes, User $user) {6 return ['user_type' => $user->type];7 })8 )9 ->create();
使用魔術方法
為了方便起見,可以使用 Laravel 的魔術 Factory 關聯方法來建立關聯。舉例來說,下列範例會使用慣例來判斷應通過 User
Model 上的 posts
關聯方法來建立關聯 Model:
1$user = User::factory()2 ->hasPosts(3)3 ->create();
1$user = User::factory()2 ->hasPosts(3)3 ->create();
在使用魔術方法建立 Factory 關聯時,可以傳入包含屬性的陣列來在關聯 Model 上複寫:
1$user = User::factory()2 ->hasPosts(3, [3 'published' => false,4 ])5 ->create();
1$user = User::factory()2 ->hasPosts(3, [3 'published' => false,4 ])5 ->create();
若 State 更改需要存取上層 Model,可以提供一個基於閉包的 State 變換:
1$user = User::factory()2 ->hasPosts(3, function (array $attributes, User $user) {3 return ['user_type' => $user->type];4 })5 ->create();
1$user = User::factory()2 ->hasPosts(3, function (array $attributes, User $user) {3 return ['user_type' => $user->type];4 })5 ->create();
Belongs To 關聯
我們已經瞭解如何使用 Factory 來建立「Has Many」關聯了,接著來看看這種關聯的想法。使用 for
方法可以用來定義使用 Factory 建立的 Model 所隸屬 (Belong To) 的上層 Model。舉例來說,我們可以建立三個隸屬於單一使用者的 App\Models\Post
Model 實體:
1use App\Models\Post;2use App\Models\User;34$posts = Post::factory()5 ->count(3)6 ->for(User::factory()->state([7 'name' => 'Jessica Archer',8 ]))9 ->create();
1use App\Models\Post;2use App\Models\User;34$posts = Post::factory()5 ->count(3)6 ->for(User::factory()->state([7 'name' => 'Jessica Archer',8 ]))9 ->create();
若已經有應與這些正在建立的 Model 關聯的上層 Model 實體,可以將該 Model 實體傳入 for
方法:
1$user = User::factory()->create();23$posts = Post::factory()4 ->count(3)5 ->for($user)6 ->create();
1$user = User::factory()->create();23$posts = Post::factory()4 ->count(3)5 ->for($user)6 ->create();
使用魔術方法
為了方便起見,可以使用 Laravel 的魔術 Factory 關聯方法來定義「Belongs To」關聯。舉例來說,下列範例會使用慣例來判斷應使用 Post
Model 上的 user
關聯方法來設定這三個貼文應隸屬於哪裡:
1$posts = Post::factory()2 ->count(3)3 ->forUser([4 'name' => 'Jessica Archer',5 ])6 ->create();
1$posts = Post::factory()2 ->count(3)3 ->forUser([4 'name' => 'Jessica Archer',5 ])6 ->create();
Many To Many 關聯
與 Has Many 關聯,「Many to Many」關聯也可以通過 has
方法建立:
1use App\Models\Role;2use App\Models\User;34$user = User::factory()5 ->has(Role::factory()->count(3))6 ->create();
1use App\Models\Role;2use App\Models\User;34$user = User::factory()5 ->has(Role::factory()->count(3))6 ->create();
Pivot 表屬性
若有需要為這些 Model 定義關聯 Pivot/中介資料表上的屬性,則可使用 hasAttached
方法。這個方法接受一個陣列,其中包含 Pivot 資料表上的屬性名稱,第二個引數則為其值:
1use App\Models\Role;2use App\Models\User;34$user = User::factory()5 ->hasAttached(6 Role::factory()->count(3),7 ['active' => true]8 )9 ->create();
1use App\Models\Role;2use App\Models\User;34$user = User::factory()5 ->hasAttached(6 Role::factory()->count(3),7 ['active' => true]8 )9 ->create();
若 State 更改需要存取關聯 Model,可以提供一個基於閉包的 State 變換:
1$user = User::factory()2 ->hasAttached(3 Role::factory()4 ->count(3)5 ->state(function (array $attributes, User $user) {6 return ['name' => $user->name.' Role'];7 }),8 ['active' => true]9 )10 ->create();
1$user = User::factory()2 ->hasAttached(3 Role::factory()4 ->count(3)5 ->state(function (array $attributes, User $user) {6 return ['name' => $user->name.' Role'];7 }),8 ['active' => true]9 )10 ->create();
若已有 Model 實體想讓正在建立的 Model 附加,可以將該 Model 實體傳入 hasAttached
方法。在此範例中,會將三個相同的角色附加給三個使用者:
1$roles = Role::factory()->count(3)->create();23$user = User::factory()4 ->count(3)5 ->hasAttached($roles, ['active' => true])6 ->create();
1$roles = Role::factory()->count(3)->create();23$user = User::factory()4 ->count(3)5 ->hasAttached($roles, ['active' => true])6 ->create();
使用魔術方法
為了方便起見,可以使用 Laravel 的魔術 Factory 關聯方法來定義 Many to Many 關聯。舉例來說,下列範例會使用慣例來判斷應通過 User
Model 上的 roles
關聯方法來建立關聯 Model:
1$user = User::factory()2 ->hasRoles(1, [3 'name' => 'Editor'4 ])5 ->create();
1$user = User::factory()2 ->hasRoles(1, [3 'name' => 'Editor'4 ])5 ->create();
Polymorphic (多型) 關聯
Polymorphic (多型) 關聯 也可以使用 Factory 來建立。Polymorphic 的「Morph Many」關聯使用與一般的「Has Many」關聯相同的方法來建立。舉例來說,若 App\Models\Post
Model 有與 App\Models\Comment
Model 的 morphMany
關聯:
1use App\Models\Post;23$post = Post::factory()->hasComments(3)->create();
1use App\Models\Post;23$post = Post::factory()->hasComments(3)->create();
Morph To 關聯
在建立 morphTo
關聯時無法使用魔法方法。必須直接使用 for
方法,並明顯提供該關聯的名稱。舉例來說,假設 Comment
Model 有個 commantable
方法,該方法定義了 morphTo
關聯。在這種情況下,我們可以直接使用 for
方法來建立三個隸屬於單一貼文的留言:
1$comments = Comment::factory()->count(3)->for(2 Post::factory(), 'commentable'3)->create();
1$comments = Comment::factory()->count(3)->for(2 Post::factory(), 'commentable'3)->create();
Polymorphic (多型) Many to Many 關聯
Polymorphic (多型)「Many to Many」(morphyToMany
/ morphedByMany
) 關聯可以像非 Polymorphic「Many to Many」關聯一樣建立:
1use App\Models\Tag;2use App\Models\Video;34$videos = Video::factory()5 ->hasAttached(6 Tag::factory()->count(3),7 ['public' => true]8 )9 ->create();
1use App\Models\Tag;2use App\Models\Video;34$videos = Video::factory()5 ->hasAttached(6 Tag::factory()->count(3),7 ['public' => true]8 )9 ->create();
當然,也可以使用 has
魔法方法來建立 Polymorphic「Many to Many」關聯:
1$videos = Video::factory()2 ->hasTags(3, ['public' => true])3 ->create();
1$videos = Video::factory()2 ->hasTags(3, ['public' => true])3 ->create();
在 Factory 中定義關聯
若要在 Model Factory 中定義關聯,則通常需要為該關聯的外部索引鍵 (Foreign Key) 指定新的 Factory 實體。一般是使用「相反」的關聯來處理,如 belongsTo
與 morphTo
關聯。舉例來說,若想在建立貼文時建立新使用者,可以像這樣:
1use App\Models\User;23/**4 * Define the model's default state.5 *6 * @return array7 */8public function definition()9{10 return [11 'user_id' => User::factory(),12 'title' => $this->faker->title(),13 'content' => $this->faker->paragraph(),14 ];15}
1use App\Models\User;23/**4 * Define the model's default state.5 *6 * @return array7 */8public function definition()9{10 return [11 'user_id' => User::factory(),12 'title' => $this->faker->title(),13 'content' => $this->faker->paragraph(),14 ];15}
若該關聯的欄位仰賴定義其的 Factory,則可以在屬性中放入閉包。該閉包會收到該 Factory 取值結果的屬性陣列:
1/**2 * Define the model's default state.3 *4 * @return array5 */6public function definition()7{8 return [9 'user_id' => User::factory(),10 'user_type' => function (array $attributes) {11 return User::find($attributes['user_id'])->type;12 },13 'title' => $this->faker->title(),14 'content' => $this->faker->paragraph(),15 ];16}
1/**2 * Define the model's default state.3 *4 * @return array5 */6public function definition()7{8 return [9 'user_id' => User::factory(),10 'user_type' => function (array $attributes) {11 return User::find($attributes['user_id'])->type;12 },13 'title' => $this->faker->title(),14 'content' => $this->faker->paragraph(),15 ];16}
執行 Seeder
若想使用資料庫 Seeder 來在功能測試時修改資料庫,則可以叫用 seed
方法。預設情況下,seed
方法會執行 DatabaseSeeder
,該 Seeder 應用來執行所有其他的 Seeder。或者,也可以傳入指定的 Seeder 類別名稱給 seed
方法:
1<?php23namespace Tests\Feature;45use Database\Seeders\OrderStatusSeeder;6use Database\Seeders\TransactionStatusSeeder;7use Illuminate\Foundation\Testing\RefreshDatabase;8use Illuminate\Foundation\Testing\WithoutMiddleware;9use Tests\TestCase;1011class ExampleTest extends TestCase12{13 use RefreshDatabase;1415 /**16 * Test creating a new order.17 *18 * @return void19 */20 public function test_orders_can_be_created()21 {22 // Run the DatabaseSeeder...23 $this->seed();2425 // Run a specific seeder...26 $this->seed(OrderStatusSeeder::class);2728 // ...2930 // Run an array of specific seeders...31 $this->seed([32 OrderStatusSeeder::class,33 TransactionStatusSeeder::class,34 // ...35 ]);36 }37}
1<?php23namespace Tests\Feature;45use Database\Seeders\OrderStatusSeeder;6use Database\Seeders\TransactionStatusSeeder;7use Illuminate\Foundation\Testing\RefreshDatabase;8use Illuminate\Foundation\Testing\WithoutMiddleware;9use Tests\TestCase;1011class ExampleTest extends TestCase12{13 use RefreshDatabase;1415 /**16 * Test creating a new order.17 *18 * @return void19 */20 public function test_orders_can_be_created()21 {22 // Run the DatabaseSeeder...23 $this->seed();2425 // Run a specific seeder...26 $this->seed(OrderStatusSeeder::class);2728 // ...2930 // Run an array of specific seeders...31 $this->seed([32 OrderStatusSeeder::class,33 TransactionStatusSeeder::class,34 // ...35 ]);36 }37}
或者,也可以使用 RefreshDatabase
Trait 來讓 Laravel 在每次測試前都自動執行資料庫 Seed。可以通過在基礎測試類別上定義 $seed
屬性來完成:
1<?php23namespace Tests;45use Illuminate\Foundation\Testing\TestCase as BaseTestCase;67abstract class TestCase extends BaseTestCase8{9 use CreatesApplication;1011 /**12 * Indicates whether the default seeder should run before each test.13 *14 * @var bool15 */16 protected $seed = true;17}
1<?php23namespace Tests;45use Illuminate\Foundation\Testing\TestCase as BaseTestCase;67abstract class TestCase extends BaseTestCase8{9 use CreatesApplication;1011 /**12 * Indicates whether the default seeder should run before each test.13 *14 * @var bool15 */16 protected $seed = true;17}
當 $seed
屬性為 true
時,各個使用了 RefreshDatabase
Trait 的測試都會在開始前先執行 Database\Seeders\DatabaseSeeder
類別。不過,也可以通過在測試類別內定義 $seeder
屬性來指定要執行的 Seeder。
1use Database\Seeders\OrderStatusSeeder;23/**4 * Run a specific seeder before each test.5 *6 * @var string7 */8protected $seeder = OrderStatusSeeder::class;
1use Database\Seeders\OrderStatusSeeder;23/**4 * Run a specific seeder before each test.5 *6 * @var string7 */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', [3]);
1$this->assertDatabaseHas('users', [3]);
assertDatabaseMissing
判斷資料庫中的某個資料表是否不包含符合給定索引鍵/值查詢條件的記錄:
1$this->assertDatabaseMissing('users', [3]);
1$this->assertDatabaseMissing('users', [3]);
assertDeleted
assertDeleted
判斷給定的 Eloquent Model 是否已從資料庫內刪除:
1use App\Models\User;23$user = User::find(1);45$user->delete();67$this->assertDeleted($user);
1use App\Models\User;23$user = User::find(1);45$user->delete();67$this->assertDeleted($user);
assertSoftDeleted
方法可用來判斷給定 Eloquent Model 是否已「軟刪除 (Soft Delete)」:
1$this->assertSoftDeleted($user);
1$this->assertSoftDeleted($user);
assertModelExists
判斷給定 Model 存在資料庫中:
1use App\Models\User;23$user = User::factory()->create();45$this->assertModelExists($user);
1use App\Models\User;23$user = User::factory()->create();45$this->assertModelExists($user);
assertModelMissing
判斷給定 Model 不存在資料庫中:
1use App\Models\User;23$user = User::factory()->create();45$user->delete();67$this->assertModelMissing($user);
1use App\Models\User;23$user = User::factory()->create();45$user->delete();67$this->assertModelMissing($user);