🐛

PHPUnitからPestPHPへ:テストをもっと軽快に!

に公開

はじめに

PHPUnit を使ってテストを書いていると、その記述量や実行時間に頭を悩ませることはありませんか?
もっと軽快に、そして読みやすくテストを書きたい――
そんな願いを叶えてくれるかもしれないと思い、「PestPHP」に触れてみました。

https://pestphp.com/

PestPHP は「読みやすく理解しやすい」ことを掲げ、既存の PHPUnit を拡張する形で機能を提供しています。そのため、既存のテスト資産を活かしつつ、段階的に導入できるのも魅力です。今回は、PestPHP の導入から基本的な使い方について説明し、その軽快さを体感してみましょう。

環境構築

推奨環境

  • PHP 8.2以上

環境構築

公式ドキュメントの通り、PestPHP を導入します。
https://pestphp.com/docs/installation

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  テックブログ

Discussion