自訂期望

Pest 的期望值 API 預設功能強大,但有時你可能需要在測試之間重複編寫相同的期望值。這種情況下,針對你的特定需求建立自訂期望值會非常有用。

自訂期望值通常定義在 tests/Pest.php 檔案中,但你也可以將它們整理在不同的 tests/Expectations.php 檔案中,以利於維護。若要在 Pest 中建立自訂期望值,將 extend() 方法連結在 expect() 函式上,但不用提供任何期望值。

例如,假設你正在測試一個數字公用程式函式庫,你需要經常斷言數字是否在給定的範圍內。這種情況下,你可以建立一個名為 toBeWithinRange() 的自訂期望值

1// Pest.php or Expectations.php...
2expect()->extend('toBeWithinRange', function (int $min, int $max) {
3 return $this->toBeGreaterThanOrEqual($min)
4 ->toBeLessThanOrEqual($max);
5});
6 
7// Tests/Unit/ExampleTest.php
8test('numeric ranges', function () {
9 expect(100)->toBeWithinRange(90, 110);
10});

雖然使用者通常在自訂期望值中利用 Pest 內建的期望值,就像在 toBeWithinRange() 範例中展示的那樣,但有時你可能需要直接存取期望值來執行你自己的自訂期望值邏輯。這種情況下,你可以透過 $this->value 屬性存取傳遞給 expect($value) 的期望值。

1expect()->extend('toBeWithinRange', function (int $min, int $max) {
2 echo $this->value; // 100
3});

當然,你可能希望使用者可以將期望值與你的自訂期望值「連結」。若要達成此事,請確保你的自訂期望值包含 return $this 陳述式。

1// Pest.php or Expectations.php...
2expect()->extend('toBeWithinRange', function (int $min, int $max) {
3 // Assertions based on `$this->value` and the given arguments...
4 
5 return $this; // Return this, so another expectations can chain this one...
6});
7 
8// Tests/Unit/ExampleTest.php
9test('numeric ranges', function () {
10 expect(100)
11 ->toBeInt()
12 ->toBeWithinRange(90, 110)
13 ->to...
14});

攔截期望值

雖然這被認為是進階做法,但透過 intercept() 方法,你可以用自己的實作覆寫現有的期望值。使用此方法時,如果期望值是指定類型,現有的期望值將被完全取代。例如,你可以取代 toBe() 期望值,以檢查 Illuminate\Database\Eloquent\Model 类型的兩個物件是否具有相同的 id

1use Illuminate\Database\Eloquent\Model;
2use App\Models\User;
3 
4// tests/Pest.php or tests/Expectations.php
5expect()->intercept('toBe', Model::class, function(Model $expected) {
6 expect($this->value->id)->toBe($expected->id);
7});
8 
9// tests/Feature/ExampleTest.php
10test('models', function () {
11 $userA = User::find(1);
12 $userB = User::find(1);
13 
14 expect($userA)->toBe($userB);
15});

與將字串類型傳遞為 intercept() 方法的第二個引數不同,你也可以傳遞一個封閉,用以決定是否覆寫核心期望值。

1expect()->intercept('toBe', fn (mixed $value) => is_string($value), function (string $expected, bool $ignoreCase = false) {
2 if ($ignoreCase) {
3 assertEqualsIgnoringCase($expected, $this->value);
4 } else {
5 assertSame($expected, $this->value);
6 }
7});

管道預期

您可能會想執行 Pest 的內建預期之一,但在特定條件下納入客製化預期邏輯。在這些情況下,您可以使用 pipe() 方法。例如,如果您給定的值是一個 Eloquent 模型,我們可能想要客製化 toBe() 預期的行為。

1use Illuminate\Database\Eloquent\Model;
2use App\Models\User;
3 
4expect()->pipe('toBe', function (Closure $next, mixed $expected) {
5 if ($this->value instanceof Model) {
6 return expect($this->value->id)->toBe($expected->id);
7 }
8 
9 return $next(); // Run to the original, built-in expectation...
10});

如所示範,建立自訂預期可以顯著簡化您的程式碼,無需重複邏輯來驗證您的測試是否按預期進行。在下一章中,我們將探討 Pest 提供的其他 CLI 選項:CLI API 參考