speeding-up-laravel-tests について
Laravel 開発者向けに、遅いテストスイートの環境設定、外部処理のフェイク、データベース負荷、プロファイリングを整理したチェックリストです。手間の少ない設定変更から確認できます。
主な機能
- 01テスト環境設定の調整
- 02外部処理のフェイク
- 03データベース準備負荷の軽減
- 04遅いテストの分析
活用シーン
- 01時間のかかる CI テストの短縮
- 02個別テストの遅延原因の調査
- 03新規プロジェクト用チェックリストの作成
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ freekmurze/ dotfiles --skill speeding-up-laravel-testsインストール後、Claude Code で/speeding-up-laravel-testsを入力して読み込まれたか確認します。
詳細
Laravel のテストを高速化する
Laravel のテストスイートを高速化するための厳選したテクニックです。おおむね記載順に適用してください。環境の修正は、通常、最小限の手間で最大の効果が得られます。
使いどき
- テストスイートの平均実行時間が、テスト1件あたり数秒を超えている場合。
- CI の所要時間が伸びており、数分短縮したい場合。
- 特定のテストが遅く、実際に何をしているのか調べたい場合。
- 新しいプロジェクトに参加するにあたり、標準的なチェックリストが必要な場合。
環境と設定
.env.testing(またはphpunit.xml)でBCRYPT_ROUNDS=4を設定します。 デフォルトは12で、認証テストではハッシュ処理が大きな負荷になります。- XDebug を無効にします。 カバレッジが必要な場合を除き、規模の大きい環境では pcov も無効にします。
- テスト環境ではバックグラウンドパッケージを無効にします。 Pulse、Telescope、Nightwatch など、リクエストやコマンドごとに処理を行うサードパーティ製パッケージが対象です。
WithCachedConfigとWithCachedRoutesトレイトを使用して、 テストごとに設定やルートを再解析しないようにします。- テストのセットアップで
withoutVite()(またはwithoutMix())を呼び出し、 フレームワークがビルド済みアセットを解決しようとしないようにします。
外部とのやり取りをフェイクする
テスト対象ではない外部サービスとのやり取りは、すべてフェイクしてください。
Notification::fake()、Mail::fake()、Bus::fake()、Event::fake()、Queue::fake()。- ジョブをディスパッチする HTTP エンドポイント: ジョブの動作を検証するテストでない限り、キューをフェイクします。そうしないと、ジョブがインラインで実行され、ジョブが依存するあらゆるものが読み込まれます。
- イベントリスナー: 無関係なリスナーが発火して処理を行う場合は、それらを
Event::fake()でフェイクします。遅いテスト中に何が発火しているかを調べるには、Laravel のイベントシステムを使用してください。 - テストスイートで
Http::preventingStrayRequests()を使用します。 たった1つの遅い意図しないリクエストでも、すべてのテストに悪影響を及ぼす可能性があります。これは Laravel の HTTP クライアント経由のリクエストのみを検出する点に注意してください。Guzzle/cURL の直接使用は別途調査してください。 Sleep::fake(syncWithCarbon: true)を使用して、 リトライやバックオフで実際にスリープしないようにします。PHP のsleep()ではなく、コードでSleepヘルパーを使用する必要があります。Exceptions::fake()を使用して、 テスト内から Flare/Sentry/Bugsnag に報告していないことを確認します。
データベース
RefreshDatabaseの代わりにLazilyRefreshDatabaseを使用します。 DB に一度もアクセスしないテストでは、マイグレーションやテーブルの切り詰めにかかるコストを完全に省けます。- ファクトリーの使用状況を監査します。 ファクトリーは、テストに必要な数を超えるモデルを簡単に作成してしまうため、よくあるボトルネックです。ネストした
create()呼び出しが余分な行を生成していないか確認してください。 $factory->recycle($model)を使用して、 共有する親モデルを一度だけ作成し、ネストしたファクトリー呼び出しに渡します。各ネストしたファクトリーが個別に親モデルを作成するのを防げます。
プロファイリングと診断
./vendor/bin/pest --profileを実行すると、 シャードごとに最も遅いテストが表示されます。まずはここから始めましょう。上位10件に見られるパターンは、スイート全体にも当てはまることがよくあります。- https://marmelab.com/phpunit-d3-report/ でテストスイートを可視化できます。 (もともとは PHPUnit 向けです。Pest との互換性を確認してください。)
- 遅いテストの原因がわからない場合は、イベントリスナーを計測するか、一時的なログを追加して、裏で発生している予期しない処理を見つけてください。
クイックリファレンス
| 領域 | 対応 |
|---|---|
| ハッシュ処理 | BCRYPT_ROUNDS=4 |
| デバッガー | XDebug を無効化、pcov を無効化 |
| バックグラウンドパッケージ | Pulse、Telescope、Nightwatch を無効化 |
| 設定/ルート | WithCachedConfig、WithCachedRoutes |
| アセット | withoutVite() / withoutMix() |
| 外部サービス | Notification::fake()、Mail::fake()、Bus::fake()、Event::fake()、Queue::fake() |
| HTTP | Http::preventingStrayRequests() |
| スリープ | Sleep::fake(syncWithCarbon: true) |
| 例外 | Exceptions::fake() |
| DB | LazilyRefreshDatabase |
| ファクトリー | $factory->recycle($model)、ネストした create() を監査 |
| プロファイリング | pest --profile |
よくある間違い
- テストでデータベースにアクセスしない場合でも、すべてのテストで
RefreshDatabaseを有効にする。 - 実際の
sleep()を呼び出したり、本番コードで Carbon を使用したりするため、Sleep::fake()を活用できなくなる。 Queue::fake()を追加したまま、ジョブの副作用をアサートする(副作用は発生しません)。- テストが失敗した場合に備えて、XDebug を読み込んだ状態でテストスイートを実行する。
.env.testingを作成していないため、BCRYPT_ROUNDSをデフォルトのままにする。
コメント
Markdown 対応