モダンなWebアプリケーション開発において、品質の担保やリファクタリングを安全に行うために「自動テスト」は欠かせない要素です。
Laravelでは長年PHPUnitが標準として利用されてきましたが、近年Laravel公式ドキュメントやエコシステム全体で強く推奨されているのが、モダンで直感的なテストフレームワーク「Pest(ペスト)」です。
Pestを採用することで、クラス構文や冗長なボイラープレート(定型文)から解放され、自然言語のように読みやすくエレガントなテストコードを書くことができます。
- Pestの基本概念とPHPUnitとの違い・メリット
- LaravelプロジェクトへのPest導入手順と初期設定(tests/Pest.php)
- Pestの基本構文(test / it)と直感的なアサーション(Expectation API)
- HTTPリクエストや認証・セッションを検証するFeatureテストの実装方法
- RefreshDatabaseとFactoryを組み合わせたデータベーステストの実践
- データセット(with)やアーキテクチャテストなどの応用テクニック
Laravelで話題のテストフレームワーク「Pest」とは?
Pestは、PHPUnitの堅牢な基盤の上に構築された、「開発者の体験(DX)」を最優先に設計されたテストフレームワークです。
JavaScriptエコシステムにおけるJestやVitestのような、関数型で表現力豊かなシンタックスを採用しており、PHP特有のクラス記述の冗長さを大幅に削減します。
Pestの特徴とPHPUnitとの違い
PHPUnitとPestの最大の違いは、「テストコードの表現力と記述量」にあります。
以下の比較表をご覧ください。
| 比較項目 | PHPUnit | Pest |
|---|---|---|
| **記述スタイル** |
クラスベース(`class UserTest extends TestCase`) | 関数・クロージャベース(`test()` / `it()`) |
| **テストメソッド** | `public function test_something()` | `test(‘something’, function () { … })` |
| **アサーション** | `$this->assertEquals()`, `$this->assertTrue()` | `expect($value)->toBe()`, `toBeTrue()` |
| **テストの可読性** | ボイラープレートが多く縦に長くなりやすい | 自然な英文のように直感的に読める |
| **互換性** | — | PHPUnitのアサーションや既存テストと100%互換 |
| **学習コスト** | オブジェクト指向の定型文を覚える必要がある | JavaScript等のテスト経験があれば即座に書ける |
PHPUnitでは1つのテストを書くためにクラス定義、名前空間のインポート、テストメソッドの定義など多くの定型文が必要でしたが、Pestでは数行のシンプルなコードで完結します。
なぜLaravel公式やコミュニティでPestが推奨されるのか?
LaravelコミュニティでPestが絶大な支持を集めている理由は以下の3点です。
- Laravelとの緊密な統合: Laravel公式プラグイン(
pest-plugin-laravel)により、$this->get()や$this->actingAs()などのヘルパーがそのまま違和感なく使用できます。 - 既存テストとの共存・移行が容易: PestはPHPUnitラッパーとして動作するため、既存のPHPUnitテストをそのまま残したまま、新しいテストファイルだけをPestで書き始めることができます。
- 洗練されたコンソール出力: テスト実行結果が美しく色分けされ、どのテストがどの行で失敗したのかが一目で分かります。
Pestの導入手順と初期設定
LaravelプロジェクトにPestを導入する手順は非常に簡単です。
ComposerでPestとLaravelプラグインをインストール
ターミナルで以下のコマンドを実行し、Pest本体とLaravel専用プラグインを開発用依存関係としてインストールします。
composer require pestphp/pest pestphp/pest-plugin-laravel --dev
初期化コマンドとtests/Pest.phpの設定
インストールが完了したら、初期化コマンドを実行します。
php artisan pest:install
このコマンドを実行すると、プロジェクトルートの tests ディレクトリ配下に Pest.php という設定ファイルが自動生成されます。
tests/Pest.php は、すべてのテストに共通する基底クラスの設定やトレイトの適用を行う重要なファイルです。
<?php
// tests/Pest.php
uses(
TestsTestCase::class,
IlluminateFoundationTestingRefreshDatabase::class,
)->in('Feature');
上記のように記述することで、tests/Feature ディレクトリ内のすべてのテストに対して RefreshDatabase(テスト実行ごとのDB初期化)が自動適用されます。個別のテストファイルで毎回トレイトを読み込む必要がなくなります。
Pestテストファイルの作成コマンド
Pest用のテストファイルを作成するには、Artisanコマンドに --pest オプションを付与するか、Pest専用のコマンドを使用します。
# Featureテストを作成する場合
php artisan make:test UserTest --pest
# Unitテストを作成する場合
php artisan make:test CalculateTest --unit --pest
生成されたテストファイル(例: tests/Feature/UserTest.php)は、最初からPestの構文で記述されています。
Pestの基本構文とアサーション(Expectation API)
Pestのテストコードは、直感的で読みやすい関数型シンタックスで構成されます。
test() と it() の使い分け
テストケースを定義する関数には test() と it() の2種類があります。機能的な違いはなく、書きたいテストの文脈に合わせて使い分けます。
// test() を使った例
test('ユーザーの合計金額が正しく計算されること', function () {
$total = 100 + 200;
expect($total)->toBe(300);
});
// it() を使った例(主語「It」に続く自然な表現)
it('can calculate user total amount', function () {
$total = 100 + 200;
expect($total)->toBe(300);
});
日本語で「〜であること」と書く場合は test()、英語で「it can 〜」「it should 〜」と書く場合は it() を使うのが一般的です。
expect() を使った直感的なアサーション記法
Pestでは、値を検証するための Expectation API(expect()) が用意されています。メソッドチェーンで自然に条件を繋げて検証できます。
// 等値・同一性の検証
expect($name)->toBe('Laravel'); // === と同等
expect($count)->toEqual(10); // == と同等
// 真偽値・Nullの検証
expect($isActive)->toBeTrue();
expect($user)->not->toBeNull();
// 配列やコレクションの検証
expect($items)->toHaveCount(3);
expect($tags)->toContain('PHP', 'Laravel');
expect($data)->toHaveKey('email');
// 数値の範囲検証
expect($score)->toBeGreaterThan(80);
expect($age)->toBeBetween(18, 65);
not 修飾子を挟むだけで「〜ではないこと」を簡単に表現できる点もPestの魅力です。
with() を使ったデータセット(パラメータ駆動テスト)
複数の入力パターンに対して同一のテストロジックを実行したい場合、with() メソッドを使ってデータプロバイダを簡潔に定義できます。
test('税率計算が正しく行われること', function ($price, $taxRate, $expected) {
$tax = $price * $taxRate;
expect($tax)->toBe($expected);
})->with([
[1000, 0.10, 100.0],
[2000, 0.08, 160.0],
[500, 0.10, 50.0],
]);
PHPUnitのように別メソッドでプロバイダを定義してアノテーションを付ける手間がなく、テストの直下にインラインでデータを渡せます。
実践!Featureテスト(HTTPリクエスト・認証)の書き方
Webアプリケーション開発で最も頻繁に作成するのが、コントローラやルーティングの挙動を検証する Featureテスト です。
GET / POST リクエストとレスポンス検証
ユーザー一覧ページの表示や新規投稿作成のテスト例です。
// tests/Feature/ArticleTest.php
it('displays the articles index page', function () {
// GETリクエストを送信
$response = $this->get('/articles');
// レスポンスのステータスコードと表示テキストを検証
$response->assertOk()
->assertSee('記事一覧');
});
it('can create a new article via POST request', function () {
$payload = [
'title' => 'Pest入門ガイド',
'content' => 'Pestの基本的な使い方を解説します。',
];
// POSTリクエストを送信
$response = $this->post('/articles', $payload);
// リダイレクトとDB保存を検証
$response->assertRedirect('/articles');
});
actingAs() を使ったログインユーザーの認証テスト
Laravel標準の actingAs() ヘルパーを使って、特定のユーザーとしてログインした状態でのリクエストをテストできます。
use AppModelsUser;
it('allows authenticated users to access dashboard', function () {
// テスト用ユーザーを生成
$user = User::factory()->create();
// ログイン状態でリクエスト
$response = $this->actingAs($user)->get('/dashboard');
$response->assertOk()
->assertSee('マイページ');
});
it('redirects guest users from dashboard to login page', function () {
// 未ログイン状態でアクセス
$response = $this->get('/dashboard');
// ログイン画面へリダイレクトされることを検証
$response->assertRedirect('/login');
});
バリデーションエラーやセッション・リダイレクトの検証
フォーム送信時にバリデーションエラーが発生した場合のテストもシンプルに記述できます。
it('requires a title when storing an article', function () {
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/articles', [
'title' => '', // 空文字にしてバリデーションエラーを誘発
'content' => '本文のみ',
]);
// セッションに特定フィールドのエラーが含まれているか検証
$response->assertSessionHasErrors(['title']);
});
データベーステストとRefreshDatabaseの実践
データベースと連携するテストでは、テストごとにデータをリセットし、テストデータを作成・検証する仕組みが必要です。
tests/Pest.php で RefreshDatabase を一括適用する設定
前述の通り、tests/Pest.php に以下のように記述しておけば、Featureテスト実行時に自動でマイグレーションが実行され、テスト終了時にロールバックされます。
// tests/Pest.php
uses(
TestsTestCase::class,
IlluminateFoundationTestingRefreshDatabase::class,
)->in('Feature');
これにより、各テストファイルで use RefreshDatabase; を個別に記述する必要がなくなります。
Factoryを活用したテストデータ生成と検証
LaravelのEloquent FactoryとPestを組み合わせることで、テストデータの作成とアサーションが非常に直感的になります。
use AppModelsArticle;
use AppModelsUser;
it('updates article status to published', function () {
$author = User::factory()->create();
$article = Article::factory()->create([
'user_id' => $author->id,
'status' => 'draft',
]);
// 公開エンドポイントへPUTリクエスト
$this->actingAs($author)->put("/articles/{$article->id}/publish");
// データベースの値が更新されたことを検証
$this->assertDatabaseHas('articles', [
'id' => $article->id,
'status' => 'published',
]);
});
assertDatabaseHas と assertDatabaseMissing の実践例
データベースに対する登録・削除の成否を判定する代表的なアサーションです。
it('can delete an article from database', function () {
$user = User::factory()->create();
$article = Article::factory()->create(['user_id' => $user->id]);
$this->actingAs($user)->delete("/articles/{$article->id}");
// レコードがテーブルから消えていることを検証
$this->assertDatabaseMissing('articles', [
'id' => $article->id,
]);
});
テストの実行・効率化コマンドと応用機能
日常の開発フローで役立つPestの実行コマンドと高度な機能を紹介します。
php artisan test コマンドによる実行とフィルタリング
PestはLaravel標準の php artisan test コマンドで実行できます。
# 全テストの実行
php artisan test
# 特定のテストファイルのみ実行
php artisan test tests/Feature/ArticleTest.php
# テスト名で絞り込んで実行(--filter)
php artisan test --filter="displays the articles"
# 失敗したテストで即座に中断(--stop-on-failure / --bail)
php artisan test --bail
並列実行(–parallel)とカバレッジ測定(–coverage)
テスト数が増えてきた場合の高速化やコード網羅率の測定もコマンド1つで行えます。
# CPUコアを活用してテストを並列実行(大幅に時間短縮)
php artisan test --parallel
# テストコードカバレッジを測定・表示
php artisan test --coverage
アーキテクチャテスト(Arch Testing)の活用
Pestには、アプリケーションの設計規約や命名規則を自動でテストできる「Arch Testing」機能が組み込まれています。
// tests/Feature/ArchitectureTest.php
// Modelsディレクトリ配下のクラスはすべてModelを継承していることを検証
arch('models')
->expect('AppModels')
->toExtend('IlluminateDatabaseEloquentModel');
// コントローラでは dd() や dump() が残っていないことを検証
arch('controllers')
->expect('AppHttpControllers')
->not->toUse(['dd', 'dump', 'ray']);
チーム開発でコードレビューの負担を減らし、クリーンな設計を維持するのに非常に強力です。
まとめ:PestでLaravelのテストを楽しくシンプルに書こう
Pestは、PHPUnitの機能性を完全に受け継ぎながら、「書きやすく、読みやすく、美しい」テスト体験を提供してくれる次世代のテスティングフレームワークです。
- クラス不要のシンプルな構文で、テスト記述のハードルが下がる
- `tests/Pest.php` で `RefreshDatabase` を一括適用し、設定の重複を排除
- `expect()` 構文により、直感的で読みやすいアサーションが可能
- PHPUnitとの完全互換により、既存プロジェクトにもノーリスクで導入可能
まずは php artisan make:test SampleTest --pest で1本のFeatureテストを書いてみて、その軽快さと可読性の高さを実感してみてください。

コメント