預期

藉由使用 Pest 預期 API 來設定測試的預期,你可以輕鬆找出程式碼中的錯誤和其他問題。這是因為此 API 允許你指定測試的預期結果,使其可以輕易地偵測出與預期行為的任何差異。

你可以將值傳遞給 expect($value) 函式來開始預期。你每次想要測試一個值時,就會使用 expect() 函式。你很少會單獨呼叫 expect()。你會使用 expect() 與「預期」方法來判斷值是否正確。

1test('sum', function () {
2 $value = sum(1, 2);
3 
4 expect($value)->toBe(3); // Assert that the value is 3...
5});

如示範所示,Pest 中的 expect 函式允許你為一個給定的 $value 串聯多個預期。這表示你可以在一個測試中執行必要的檢查次数,只需要持續串聯其他預期即可。

1expect($value)
2 ->toBeInt()
3 ->toBe(3);

你可以隨時在預期之前加上 not 修飾詞來測試相反的預期。

1expect($value)
2 ->toBeInt()
3 ->toBe(3)
4 ->not->toBeString() // Not to be string...
5 ->not->toBe(4); // Not to be 4...

藉由使用 Pest 預期 API,你可以存取許多用於測試不同程式碼區塊的個別預期。以下提供可用預期的完整清單。

除了 Pest 中提供的個別預期之外,預期 API 還提供幾個修改器,讓你可以進一步自訂你的測試。這些修改器可用于創建更複雜的預期並一次測試多個值。以下是 Pest 中可用的修改器的一些範例:


toBe()

這個預期確保 $value$expected 共享相同的類型和值。

如果用於物件,它確保兩個變數參照完全相同的物件。

1expect(1)->toBe(1);
2expect('1')->not->toBe(1);
3expect(new StdClass())->not->toBe(new StdClass());

toBeBetween()

這個預期確保 $value 介於兩個值之間。它適用於 intfloatDateTime

1expect(2)->toBeBetween(1, 3);
2expect(1.5)->toBeBetween(1, 2);
3 
4$expectationDate = new DateTime('2023-09-22');
5$oldestDate = new DateTime('2023-09-21');
6$latestDate = new DateTime('2023-09-23');
7 
8expect($expectationDate)->toBeBetween($oldestDate, $latestDate);

toBeEmpty()

這個預期確保 $value 為空。

1expect('')->toBeEmpty();
2expect([])->toBeEmpty();
3expect(null)->toBeEmpty();

toBeTrue()

這個預期確保 $value 為真。

1expect($isPublished)->toBeTrue();

toBeTruthy()

這個預期確保 $value 為真值。

1expect(1)->toBeTruthy();
2expect('1')->toBeTruthy();

toBeFalse()

這個預期確保 $value 為假。

1expect($isPublished)->toBeFalse();

toBeFalsy()

這個預期確保 $value 為假值。

1expect(0)->toBeFalsy();
2expect('')->toBeFalsy();

toBeGreaterThan($expected)

這個預期確保 $value 大於 $expected

1expect($count)->toBeGreaterThan(20);

toBeGreaterThanOrEqual($expected)

這個預期確保 $value 大於或等於 $expected

1expect($count)->toBeGreaterThanOrEqual(21);

toBeLessThan($expected)

這個預期確保 $value 小於 $expected

1expect($count)->toBeLessThan(3);

toBeLessThanOrEqual($expected)

這個預期確保 $value 小於或等於 $expected

1expect($count)->toBeLessThanOrEqual(2);

toContain($needles)

這個預期確保所有指定的 needles 都是 $value 中的元素。

1expect('Hello World')->toContain('Hello');
2expect('Pest: an elegant PHP Testing Framework')->toContain('Pest', 'PHP', 'Framework');
3expect([1, 2, 3, 4])->toContain(2, 4);

toContainEqual($needles)

這個預期確保所有指定的 needles 是 $value 中的元素(在相等意義上)。

1expect([1, 2, 3])->toContainEqual('1');
2expect([1, 2, 3])->toContainEqual('1', '2');

toContainOnlyInstancesOf($class)

這個預期確保 $value 僅包含 $class 的實例。

1$dates = [new DateTime(), new DateTime()];
2 
3expect($dates)->toContainOnlyInstancesOf(DateTime::class);

toHaveCount(int $count)

此期望可確保所提供的 $count 與可迭代 $value 中的元素數量相符。

1expect(['Nuno', 'Luke', 'Alex', 'Dan'])->toHaveCount(4);

toHaveProperty(string $name, $value = null)

此期望可確保 $value 具有名為 $name 的屬性。

此外,您可以透過提供第二個參數來驗證屬性的實際值。

1expect($user)->toHaveProperty('name');
2expect($user)->toHaveProperty('name', 'Nuno');
3expect($user)->toHaveProperty('is_active', 'true');

toHaveProperties(iterable $name)

此期望可確保 $value 具有與 $names 中所有名稱相符的屬性名稱。

1expect($user)->toHaveProperties(['name', 'email']);

此外,您可以使用關聯陣列驗證多個屬性的名稱和值。

1expect($user)->toHaveProperties([
2 'name' => 'Nuno',
3 'email' => 'enunomaduro@gmail.com'
4]);

toMatchArray($array)

此期望可確保 $value 陣列與指定的 $array 子集相符。

1$user = [
2 'id' => 1,
3 'name' => 'Nuno',
4 'email' => 'enunomaduro@gmail.com',
5 'is_active' => true,
6];
7 
8expect($user)->toMatchArray([
9 'email' => 'enunomaduro@gmail.com',
10 'name' => 'Nuno'
11]);

toMatchObject($object)

此期望可確保 $value 物件符合已提供 $object 部份屬性的子集。

1$user = new stdClass();
2$user->id = 1;
3$user->email = 'enunomaduro@gmail.com';
4$user->name = 'Nuno';
5 
6expect($user)->toMatchObject([
7 'email' => 'enunomaduro@gmail.com',
8 'name' => 'Nuno'
9]);

toEqual($expected)

此期望可確保 $value$expected 具有相同的數值。

1expect($title)->toEqual('Hello World');
2expect('1')->toEqual(1);
3expect(new StdClass())->toEqual(new StdClass());

toEqualCanonicalizing($expected)

此期望可確保 $value$expected 具有相同的數值,不論提供元素的順序為何。

1$usersAsc = ['Dan', 'Fabio', 'Nuno'];
2$usersDesc = ['Nuno', 'Fabio', 'Dan'];
3 
4expect($usersAsc)->toEqualCanonicalizing($usersDesc);
5expect($usersAsc)->not->toEqual($usersDesc);

toEqualWithDelta($expected, float $delta)

此期望可確保 $value$expected 的絕對差低於 $delta

1expect($durationInMinutes)->toEqualWithDelta(10, 5); //duration of 10 minutes with 5 minutes tolerance
2 
3expect(14)->toEqualWithDelta(10, 5); // Pass
4expect(14)->toEqualWithDelta(10, 0.1); // Fail

toBeIn()

此期望可確保 $value 是其中一個給定值。

1expect($newUser->status)->toBeIn(['pending', 'new', 'active']);

toBeInfinite()

此期望可確保 $value 無限大。

1expect(log(0))->toBeInfinite();

toBeInstanceOf($class)

此期望可確保 $value$class 的實例。

1expect($user)->toBeInstanceOf(User::class);

toBeArray()

此期望可確保 $value 是個陣列。

1expect(['Pest','PHP','Laravel'])->toBeArray();

toBeBool()

此期望可確保 $value 的類型為布林。

1expect($isActive)->toBeBool();

toBeCallable()

此期望可確保 $value 的類型可呼叫。

1$myFunction = function () {};
2 
3expect($myFunction)->toBeCallable();

toBeFile()

此期望可確保字串 $value 為現有的檔案。

1expect('/tmp/some-file.tmp')->toBeFile();

toBeFloat()

此期望可確保 $value 的類型為浮點數。

1expect($height)->toBeFloat();

toBeInt()

此期望可確保 $value 的類型為整數。

1expect($count)->toBeInt();

toBeIterable()

此期望可確保 $value 的類型可迭代。

1expect($array)->toBeIterable();

toBeNumeric()

此期望可確保 $value 的類型為數值。

1expect($age)->toBeNumeric();
2expect(10)->toBeNumeric();
3expect('10')->toBeNumeric();

toBeDigits()

此預期值確保 $value 僅包含數字。

1expect($year)->toBeDigits();
2expect(15)->toBeDigits();
3expect('15')->toBeDigits();

toBeObject()

此預期值確保 $value 的型別為物件。

1$object = new stdClass();
2 
3expect($object)->toBeObject();

toBeResource()

此預期值確保 $value 的型別為資源。

1$handle = fopen('php://memory', 'r+');
2 
3expect($handle)->toBeResource();

toBeScalar()

此預期值確保 $value 的型別為純量。

1expect('1')->toBeScalar();
2expect(1)->toBeScalar();
3expect(1.0)->toBeScalar();
4expect(true)->toBeScalar();
5expect([1, '1'])->not->toBeScalar();

toBeString()

此預期值確保 $value 的型別為字串。

1expect($string)->toBeString();

toBeJson()

此預期值確保 $value 是 JSON 字串。

1expect('{"hello":"world"}')->toBeJson();

toBeNan()

此預期值確保 $value 不是數字 (NaN)。

1expect(sqrt(-1))->toBeNan();

toBeNull()

此預期值確保 $value 是 null。

1expect(null)->toBeNull();

toHaveKey(string $key)

此預期值確保 $value 包含提供的 $key

1expect(['name' => 'Nuno', 'surname' => 'Maduro'])->toHaveKey('name');
2expect(['name' => 'Nuno', 'surname' => 'Maduro'])->toHaveKey('name', 'Nuno');
3expect(['user' => ['name' => 'Nuno', 'surname' => 'Maduro']])->toHaveKey('user.name');
4expect(['user' => ['name' => 'Nuno', 'surname' => 'Maduro']])->toHaveKey('user.name', 'Nuno');

toHaveKeys(array $keys)

此預期值確保 $value 包含提供的 $keys

1expect(['id' => 1, 'name' => 'Nuno'])->toHaveKeys(['id', 'name']);
2expect(['message' => ['from' => 'Nuno', 'to' => 'Luke'] ])->toHaveKeys(['message.from', 'message.to']);

toHaveLength(int $number)

此預期值確保提供的 $number 與字串 $value 的長度或可迭代 $value 中的元素數目相符。

1expect('Pest')->toHaveLength(4);
2expect(['Nuno', 'Maduro'])->toHaveLength(2);

toBeDirectory()

此預期值確保字串 $value 是目錄。

1expect('/tmp')->toBeDirectory();

toBeReadableDirectory()

此預期值確保字串 $value 是目錄且可讀取。

1expect('/tmp')->toBeReadableDirectory();

toBeReadableFile()

此預期值確保字串 $value 是檔案且可讀取。

1expect('/tmp/some-file.tmp')->toBeReadableFile();

toBeWritableDirectory()

此預期值確保字串 $value 是目錄且可寫入。

1expect('/tmp')->toBeWritableDirectory();

toBeWritableFile()

此預期值確保字串 $value 是檔案且可寫入。

1expect('/tmp/some-file.tmp')->toBeWritableFile();

toStartWith(string $expected)

此預期值確保 $value 以提供的字串開頭。

1expect('Hello World')->toStartWith('Hello');

toThrow()

此預期值確保封閉會擲出特定的例外類別、例外訊息,或兩者皆是。

1expect(fn() => throw new Exception('Something happened.'))->toThrow(Exception::class);
2expect(fn() => throw new Exception('Something happened.'))->toThrow('Something happened.');
3expect(fn() => throw new Exception('Something happened.'))->toThrow(Exception::class, 'Something happened.');
4expect(fn() => throw new Exception('Something happened.'))->toThrow(new Exception('Something happened.'));

toMatch(string $expression)

此預期值確保 $value 與正規表示式相符。

1expect('Hello World')->toMatch('/^hello wo.*$/i');

toEndWith(字串 $預期值)

此預期值確保 $值 以提供的字串結尾。

1expect('Hello World')->toEndWith('World');

toMatchConstraint(約束 $約束)

此預期值確保 $值 相符特定的 PHPUnit 約束。

1use PHPUnit\Framework\Constraint\IsTrue;
2 
3expect(true)->toMatchConstraint(new IsTrue());

toBeUppercase(字串 $預期值)

此預期值確保 $值 為大寫。

1expect('PESTPHP')->toBeUppercase();

toBeLowercase(字串 $預期值)

此預期值確保 $值 為小寫。

1expect('pestphp')->toBeLowercase();

toBeAlpha(字串 $預期值)

此預期值確保 $值 僅包含英文字母字元。

1expect('pestphp')->toBeAlpha();

toBeAlphaNumeric(字串 $預期值)

此預期值確保 $值 僅包含英數字元。

1expect('pestPHP123')->toBeAlphaNumeric();

toBeSnakeCase()

此預期值確保 $值 僅包含蛇形大小寫格式的字串。

1expect('snake_case')->toBeSnakeCase();

toBeKebabCase()

此預期值確保 $值 僅包含連字號大小寫格式的字串。

1expect('kebab-case')->toBeKebabCase();

toBeCamelCase()

此預期值確保 $值 僅包含駝峰大小寫格式的字串。

1expect('camelCase')->toBeCamelCase();

toBeStudlyCase()

此預期值確保 $值 僅包含帕斯卡大小寫格式的字串。

1expect('StudlyCase')->toBeStudlyCase();

toHaveSnakeCaseKeys()

此預期值確保 $值 僅包含鍵值為蛇形大小寫格式的陣列。

1expect(['snake_case' => 'abc123'])->toHaveSnakeCaseKeys();

toHaveKebabCaseKeys()

此預期值確保 $值 僅包含鍵值為連字號大小寫格式的陣列。

1expect(['kebab-case' => 'abc123'])->toHaveKebabCaseKeys();

toHaveCamelCaseKeys()

此預期值確保 $值 僅包含鍵值為駝峰大小寫格式的陣列。

1expect(['camelCase' => 'abc123'])->toHaveCamelCaseKeys();

toHaveStudlyCaseKeys()

此預期值確保 $值 僅包含鍵值為帕斯卡大小寫格式的陣列。

1expect(['StudlyCase' => 'abc123'])->toHaveStudlyCaseKeys();

toHaveSameSize()

此預期值確保 $值 與提供的可疊代物件的大小相同。

1expect(['foo', 'bar'])->toHaveSameSize(['baz', 'bazz']);

toBeUrl()

此預期值確保 $值 為 URL。

1expect('https://pest.dev.org.tw/')->toBeUrl();

toBeUuid()

此預期值確保 $值 為 UUID。

1expect('ca0a8228-cdf6-41db-b34b-c2f31485796c')->toBeUuid();

and($值)

and() 修飾子允許您傳遞新的 $值,讓您在單一測試中串連多個預期值。

1expect($id)->toBe(14)
2 ->and($name)->toBe('Nuno');

dd()

dd() 修飾子

使用 dd() 修改器允許你轉儲目前預期的 $value,並中止程式碼執行。這在除錯時會很有用,可以讓你檢測在測試中某個特定時間點上,$value 的目前狀態。

1expect(14)->dd(); // 14
2expect([1, 2])->sequence(
3 fn ($number) => $number->toBe(1),
4 fn ($number) => $number->dd(), // 2
5);

ddWhen($condition)

使用 ddWhen() 修改器允許你在指定 $condition 為真時,轉儲目前預期的 $value 並中止程式碼執行。

1expect([1, 2])->each(
2 fn ($number) => $number->ddWhen(fn (int $number) => $number === 2) // 2
3);

ddUnless($condition)

使用 ddUnless() 修改器允許你在指定 $condition 為假時,轉儲目前預期的 $value 並中止程式碼執行。

1expect([1, 2])->each(
2 fn ($number) => $number->ddUnless(fn (int $number) => $number === 1) // 2
3);

each()

each() 修改器允許你針對可迭代物件的每一個項目建立預期。它的運作方式是迭代可迭代物件上的每個項目,並對每一個項目套用預期。

1expect([1, 2, 3])->each->toBeInt();
2expect([1, 2, 3])->each->not->toBeString();
3expect([1, 2, 3])->each(fn ($number) => $number->toBeLessThan(4));

json()

json() 修改器將目前預期的 $value 從 JSON 編碼為陣列。

1expect('{"name":"Nuno","credit":1000.00}')
2 ->json()
3 ->toHaveCount(2)
4 ->name->toBe('Nuno')
5 ->credit->toBeFloat();
6 
7expect('not-a-json')->json(); //Fails

match()

match() 修改器會執行與第一個陣列鍵相關聯的封閉,其值與提供給該方法的第一個引數中值相符。

1expect($user->miles)
2 ->match($user->status, [
3 'new' => fn ($userMiles) => $userMiles->ToBe(0),
4 'gold' => fn ($userMiles) => $userMiles->toBeGreaterThan(500),
5 'platinum' => fn ($userMiles) => $userMiles->toBeGreaterThan(1000),
6 ]);

若要檢查預期值是否等於與配對鍵相關聯的值,你可以直接將預期值傳遞為陣列值,而不使用封閉。

1expect($user->default_language)
2 ->match($user->country, [
3 'PT' => 'Português',
4 'US' => 'English',
5 'TR' => 'Türkçe',
6 ]);

not

not 修改器允許反轉後續預期。

1expect(10)->not->toBeGreaterThan(100);
2expect(true)->not->toBeFalse();

ray()

ray() 修改器允許你透過 myray.app 除錯目前的 $value

1expect(14)->ray(); // 14
2expect([1, 2])->sequence(
3 fn ($number) => $number->toBe(1),
4 fn ($number) => $number->ray(), // 2
5);

sequence()

sequence() 修改器允許你為單一可迭代物件指定順序預期的組合。

1expect([1, 2, 3])->sequence(
2 fn ($number) => $number->toBe(1),
3 fn ($number) => $number->toBe(2),
4 fn ($number) => $number->toBe(3),
5);

sequence() 修改器也可使用於關聯式可迭代物件。每一個封閉在順序中會收到兩個引數:第一個引數是值預期,第二個引數是鍵預期。

1expect(['hello' => 'world', 'foo' => 'bar', 'john' => 'doe'])->sequence(
2 fn ($value, $key) => $value->toEqual('world'),
3 fn ($value, $key) => $key->toEqual('foo'),
4 fn ($value, $key) => $value->toBeString(),
5);

sequence() 修改器也可使用於檢查可迭代物件中的各個值是否配對一組預期值。在這種情況下,你可以直接將預期值傳遞給 sequence() 方法,而不使用封閉。

1expect(['foo', 'bar', 'baz'])->sequence('foo', 'bar', 'baz');

when()

when() 修改器在傳遞給該方法的第一個引數評量為真時執行所提供的呼叫回程式。

1expect($user)
2 ->when($user->is_verified === true, fn ($user) => $user->daily_limit->toBeGreaterThan(10))
3 ->email->not->toBeEmpty();

unless()

unless() 修改器在傳遞給該方法的第一個引數評量為假時執行所提供的呼叫回程式。

1expect($user)
2 ->unless($user->is_verified === true, fn ($user) => $user->daily_limit->toBe(10))
3 ->email->not->toBeEmpty();

在學習如何撰寫預期後,文件中的下一節,"Hooks",涵蓋了有用的函式,例如"beforeEach" 與 "afterEach",可協助設定測試的前置條件和清除動作: Hooks →