高階測試
儘管「高階測試」乍看之下似乎是一個複雜的術語,但它實際上是一個簡化測試的技術,而且是完全可選的。Pest 的核心哲學之一是鼓勵使用者像關注原始碼一樣,關注測試套件的美感和簡潔。因此,你可能會覺得這個技術很有趣,並選擇在程式碼的某些部分採用它。
我們來考慮一個範例,說明如何將現有測試遷移到高階測試。為了說明,我們將使用一個簡單的測試。
1it('works', function () {2 $this->get('/')3 ->assertStatus(200);4});
根據這個範例,你可以看到測試的全部內容是在 $this
變數上進行的鏈式呼叫。在這種情況下,可以完全移除測試閉包,並將所需的方法直接鏈接到 it()
函式。
1it('works')2 ->get('/')3 ->assertStatus(200);
移除閉包函式並將測試主體的方法直接鏈接到 test()
或 it()
函式的技術通常稱為「高階測試」。這種方法可以大幅簡化測試套件的程式碼。
這個技術也可以與 預期結果 API 結合使用。我們來看一個測試,它使用預期結果 API 來驗證使用者是否以正確的名稱建立。
1it('has a name', function () {2 $user = User::create([3 'name' => 'Nuno Maduro',4 ]);5 6 expect($user->name)->toBe('Nuno Maduro');7});
如果你的測試只包含一個預期結果,我們可以使用高階測試來簡化它。
1it('has a name')2 ->expect(fn () => User::create(['name' => 'Nuno Maduro'])->name)3 ->toBe('Nuno Maduro');
傳遞一個閉包給 expect()
方法對於預期結果值採用延遲評估至關重要。這能確保預期結果只在測試執行時建立,而不是之前。
如果你需要對在執行階段需要延遲評估的物件進行斷言,可以使用 defer()
方法。
1it('creates admins')2 ->defer(fn () => $this->artisan('user:create --admin'))3 ->assertDatabaseHas('users', ['id' => 1]);
在上面的範例中,assertDatabaseHas()
斷言方法將會在傳遞給 defer()
方法的閉包的結果上進行呼叫。
高階測試的原則也可以套用在勾子上。這表示如果勾子的主體包含一系列連結到變數 $this
的方法,你可以直接將這些方法連結到勾子方法,而完全省略封閉。
1beforeEach(function () {2 $this->withoutMiddleware();3});4 5// Can be rewritten as...6beforeEach()->withoutMiddleware();
使用高階測試時,資料集值會為了方便起見傳遞到 expect()
和 defer()
封閉。
1it('validates emails')2 ->with(['taylor@laravel.com', 'enunomaduro@gmail.com'])3 ->expect(fn (string $email) => Validator::isValid($email))4 ->toBeTrue();
高階期望
使用高階期望,你可以直接在期望值 $value
的 屬性
或 方法
上執行期望。
舉例來說,想像你在測試一個使用者是否已成功建立,以及資料庫中已儲存許多屬性。你的測試可能會類似以下
1expect($user->name)->toBe('Nuno');2expect($user->surname)->toBe('Maduro');3expect($user->addTitle('Mr.'))->toBe('Mr. Nuno Maduro');
要使用高階期望,你只要將屬性和方法直接連結到 expect()
函數上,然後 Pest 會負責擷取屬性值或在受測的 $value
上叫用方法。
現在讓我們看看相同測試經由轉換為高階期望後的結果。
1expect($user)2 ->name->toBe('Nuno')3 ->surname->toBe('Maduro')4 ->addTitle('Mr.')->toBe('Mr. Nuno Maduro');
與陣列搭配使用時,你也可以存取 $value
陣列金鑰並對其執行期望。
1expect(['name' => 'Nuno', 'projects' => ['Pest', 'OpenAI', 'Laravel Zero']])2 ->name->toBe('Nuno')3 ->projects->toHaveCount(3)4 ->each->toBeString();5 6expect(['Dan', 'Luke', 'Nuno'])7 ->{0}->toBe('Dan');
高階期望可以用於所有 期望,你甚至可以在封閉中再創造更多的期待。
1expect(['name' => 'Nuno', 'projects' => ['Pest', 'OpenAI', 'Laravel Zero']])2 ->name->toBe('Nuno')3 ->projects->toHaveCount(3)4 ->sequence(5 fn ($project) => $project->toBe('Pest'),6 fn ($project) => $project->toBe('OpenAI'),7 fn ($project) => $project->toBe('Laravel Zero'),8 );
具範圍的高階期望
使用具範圍的高階期望,你可以使用 scoped()
方法和封閉來獲得存取權並鎖定鏈中的特定層級中以完成的期望。
這對於 Laravel Eloquent 模型相當有用,因為你可以針對子關聯檢查屬性。
1expect($user)2->name->toBe('Nuno')3->email->toBe('enunomaduro@gmail.com')4->address()->scoped(fn ($address) => $address5 ->line1->toBe('1 Pest Street')6 ->city->toBe('Lisbon')7 ->country->toBe('Portugal')8);
儘管高階測試乍看之下可能會很複雜,但它是一種可以明顯簡化你的測試組代碼的技術。在下一章節中,我們將討論 Pest 社群的影片資源:影片資源