PHPUnitからPestPHPへ:テストをもっと軽快に!
はじめに
PHPUnit を使ってテストを書いていると、その記述量や実行時間に頭を悩ませることはありませんか?
もっと軽快に、そして読みやすくテストを書きたい――
そんな願いを叶えてくれるかもしれないと思い、「PestPHP」に触れてみました。
PestPHP は「読みやすく理解しやすい」ことを掲げ、既存の PHPUnit を拡張する形で機能を提供しています。そのため、既存のテスト資産を活かしつつ、段階的に導入できるのも魅力です。今回は、PestPHP の導入から基本的な使い方について説明し、その軽快さを体感してみましょう。
環境構築
推奨環境
- PHP 8.2以上
環境構築
公式ドキュメントの通り、PestPHP を導入します。
composer remove phpunit/phpunit
composer require pestphp/pest --dev --with-all-dependencies
次に PestPHP の初期設定を行います。
./vendor/bin/pest --init
最後にテストコードを実行してみます。
./vendor/bin/pest
PASS Tests\Unit\ExampleTest
✓ that true is true 0.04s
PASS Tests\Feature\ExampleTest
✓ the application returns a successful response 0.85s
Laravel を使用している方はプラグインの導入をおすすめします
Laravel のテストヘルパーの簡略化 や 新たな Artisan コマンドが使えて便利になります。
composer require pestphp/pest-plugin-laravel --dev
実践
基本形
PestPHP の構文はシンプルで読みやすく、
BDD(Behavior-Driven Development)を意識することができます。
// PestPHP
it('registers a user successfully', function () {
// テスト内容
});
// PHPUnit
class User extends TestCase
{
public function test_register(): void
{
// テスト内容
}
}
アサーション
PestPHP では、expect()
関数とチェイン可能なメソッドを使ってアサーションします。
これにより、コードがより直感的になります。
また、$this
を書かない分、記述量が少ないので読みやすく感じました。
// PestPHP
it('adds two numbers correctly', function () {
$result = 1 + 2;
expect($result)->toEqual(3);
});
// PHPUnit
public function adds_two_numbers_correctly(): void
{
$result = 1 + 2;
$this->assertEquals(3, $result);
}
データプロバイダ
PestPHP では、with()
メソッドを使って、データプロバイダをインラインで定義します。
これにより、テストコードごとに異なるデータを提供できるため、柔軟なテストが可能です。
// PestPHP
it('calculates the sum correctly with data provider', function (int $a, int $b, int $expected) {
expect($a + $b)->toEqual($expected);
})->with([
[1, 2, 3],
[5, 5, 10],
[-1, 1, 0],
]);
// PHPUnit
#[DataProvider('dataProvider')]
public function test_sum(int $a, int $b, int $expected): void
{
$this->assertEquals($expected, $a + $b);
}
public static function dataProvider(): iterable
{
return [
[1, 2, 3],
[5, 5, 10],
[-1, 1, 0],
];
}
フック
PestPHP のフックは、概念的には PHPUnit と大きな違いはありません。
ただ、細かいところでいうと、PHPUnit 特有のparent::setUp()
の記述が不要だったりと、地味に嬉しいところがあります。これにより、テストコードの記述に集中できる気がします。
Laravel プロジェクトでの具体的な記述例を見てみましょう。
//PestPHP
beforeEach(function () {
$this->loggedInUser = User::factory()->create();
actingAs($this->loggedInUser);
});
// PHPUnit
public function setUp(): void
{
parent::setUp();
$this->loggedInUser = User::factory()->create();
$this->actingAs($this->loggedInUser);
}
まとめ
今回、初めて PestPHP に触れて、その軽快さを実感できました。
私の中で感じたメリット・デメリットは以下の通りです。
メリット
- クラスやメソッドの定型文が不要で、テストの意図を直接書ける
- アサーションが直感的なチェインメソッドで書きやすい
- (Laravel の場合)Laravel が公式でサポートしてて、エコシステムが充実している
デメリット
- PHPUnit に比べて、まだ参考文献が少ない
- 内部的には PHPUnit を利用しているため、PHPUnit の基本的な知識が追加で必要になる
- PHPUnit に慣れている方は、BDD スタイルに慣れるのに時間がかかる可能性がある
メリットでも書いた通り、テストの意図を直接書ける形なので気に入りました。
PHPUnit だと、テストの目的や挙動を補足するために PHPDoc などを活用する必要があり、テストコード自体で意図を伝えるのが難しいと感じることがありました。
あと試していないですが、PHPUnit から PestPHP に変換するライブラリ pestphp/pest-plugin-drift もあり、PestPHPが 導入しやすい形になってきていると感じています。
えんさがそっ♪でも Laravel を使用していることもあり、PestPHP の動向を随時キャッチアップしていきたいと思います!

私たち BABY JOB は、子育てを取り巻く社会のあり方を変え、「すべての人が子育てを楽しいと思える社会」の実現を目指すスタートアップ企業です。圧倒的なぬくもりと当事者意識をもって、子どもと向き合う時間、そして心のゆとりが生まれるサービスを創出します。baby-job.co.jp/
Discussion