Pest 對我來說提供了更便捷的測試方式和直譯式的寫法,類似 JS 相關的測試框架,同時又保留了 Laravel 和 PHP 龐大的輔助函數和功能。
主結構
$ composer require pestphp/pest --dev --with-all-dependencies
$ ./vendor/bin/pest --init
$ ./vendor/bin/pest
folders:
├── 📂 tests
│ ├── 📂 Unit
│ │ └── ExampleTest.php
│ └── 📂 Feature
│ │ └── ExampleTest.php
│ └── TestCase.php
│ └── Pest.php
├── phpunit.xml
簡單示例
這邊可以自己添加 phpunit.xml
對應路徑,可以看到 Pest.php
實現細節:
這邊表示注入 TestCase
到 Feature 底下,可以使用 TestCase
裡面所提供的方法,當然也可以注入對應的方法到指定的 folder 底下:
uses(
Tests\TestCase::class,
// Illuminate\Foundation\Testing\RefreshDatabase::class,
)->in('Feature');
SumTest
<?php
function sum(int $int, int $int1)
{
return $int + $int1;
}
test('sum', function () {
$result = sum(1, 2);
expect($result)->toBe(3);
});
it('performs sums', function () {
$result = sum(1, 2);
expect($result)->toBe(3);
});
Pest 提供相當多的 expectations 當然你也可以自行擴展:
expect()->extend('toBeSureStatusEnabled', function (int $expected) {
return $this->toEqual($expected);
});
Hooks
這邊提供事件鉤子來讓你作 injection 和相關初始化參數動作。
以常用情境來說,我會需要測試 UserRepository
相關對應方法,我希望他能在 beforeEach
之前建立:
UserRepository.php
class UserRepository
{
public function __construct(protected User $user) {}
public function create(array $attributes = []): User
{
return $this->user->create($attributes);
}
}
UserRepositoryTest.php
beforeEach(function () {
$this->userRepository = app(\App\Repositories\UserRepository::class);
});
it('created a user.', function () {
$user = $this->userRepository->create([
'name' => $name = fake()->name(),
'email' => $email = fake()->unique()->safeEmail(),
'hash' => gzcompress(Str::random()),
'email_verified_at' => now(),
'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password
'remember_token' => Str::random(10),
]);
expect($user)->toBeInstanceOf(\App\Models\User::class);
$this->assertDatabaseHas('users', [
'name' => $name,
'email' => $email,
]);
});
Datasets
這個功能其實就像是 dataprovider
這樣理解就會比較容易了。
it('has emails', function (string $email) {
expect($email)->not->toBeEmpty();
})->with(['[email protected]', '[email protected]']);
Exceptions
就是原本的 expectsExceptions
:
it('throws exception', function () {
throw new Exception('Something happened.');
})->throws(Exception::class);
還有幾個後續支持的 --parallel
, --processes
等優化測試參數都有支持,此外我自己是比較喜歡 --profile
這個功能可以讓我知道我哪些測試在執行效能上有問題:
Tests: 6 passed (7 assertions)
Duration: 14.66s
Top 10 slowest tests:
Tests\Feature\ExampleTest > the application returns a successful response 4.42s
Tests\Feature\SumTest > it has emails with ('[email protected]') 3.22s
Tests\Feature\SumTest > it created a user. 1.22s
Tests\Feature\SumTest > it has emails with ('[email protected]') 0.42s
Tests\Feature\SumTest > it performs sums 0.32s
Tests\Unit\ExampleTest > that true is true 0.19s
───────────────────────────────────────────────────────────────────────────────────────────────
(66.75% of 14.66s) 9.79s
總結
整體來說我覺得作為一款輔助 unit testing 的協同框架是非常不錯的,它提供一種流暢和易懂的寫法來撰寫單元測試,但必須注意的是它底層一樣是依賴 phpunit 框架,所以還是需要知道 phpunit 是如何使用跟運作,而把 pest 當成是一種協同、換個方式描述的測試框架使用會比較好,我認為他情境適合用於穩定且探索新做法的專案當中,初期專案我還是會比較傾向於使用內建的作法會比較方便協作。