株式会社織翔
← コラム一覧に戻る
DevOps7分で読める

GitHub ActionsでLaravelのテストを自動化する基本

Laravelプロジェクトでphp artisan testを自動実行するために、GitHub Actionsの役割、ワークフロー構成、導入時の確認観点を整理します。

#GitHub Actions#Laravel#CI/CD#テスト自動化

GitHub Actionsでテストを自動化する理由

Laravelに限らず、Webシステムは**小さな修正でも思わぬ場所に影響が出ます。**フォームのバリデーションを直しただけのつもりでも、認証、通知、管理画面、APIレスポンス、バッチ処理など、利用者から見えない処理に影響することがあります。

手元で毎回テストを実行できれば理想ですが、急ぎの修正や複数人での開発では抜け漏れが起きやすくなります。そこでGitHub Actionsを使い、pushやPull Requestのタイミングで php artisan test を自動実行しておくと、最低限の確認を人の記憶に頼らず回せます。

CIは「人が確認しなくてよい仕組み」ではなく、「毎回同じ条件で確認するための仕組み」です。

まず決めるべき運用ルール

ワークフローを書く前に、先に運用を決めておくと失敗しにくくなります。

  • どのブランチへのpushで実行するか
  • Pull Request作成時にも実行するか
  • テスト失敗時にマージを止めるか
  • 失敗時に誰が確認するか
  • テスト用DBや外部サービスをどう扱うか
  • CIで実行する範囲を単体テスト中心にするか、Featureテストまで含めるか

特に重要なのは、CIの結果をチームがどう扱うかです。失敗していても毎回無視する運用になると、**CIは形だけの仕組みになります。**逆に、最初から完璧を求めすぎると、CIの整備に時間を使いすぎて導入が進みません。

Laravelテストの基本

Laravelでは、tests/Unittests/Feature にテストを分けて管理する構成が一般的です。Unitテストは小さな処理の確認に向き、FeatureテストはHTTPリクエストや複数の処理が連動する動作確認に向いています。

テスト実行には、Laravel標準の php artisan test を使えます。PestやPHPUnitを直接実行することもできますが、まずはプロジェクト内で普段使うコマンドをCIにも載せると、ローカルとCIの差分を小さくできます。

php artisan test

Laravelはテスト実行時に testing 環境を使います。必要に応じて .env.testing を用意し、DB接続や外部APIキーなどを本番・開発環境と切り分けます。設定キャッシュが残っていると意図した環境変数が読まれないことがあるため、CI内で php artisan config:clear を入れる判断もあります。

最小構成のワークフロー例

Laravelで最低限のテストを動かす場合、構成は次のようになります。

name: Laravel Test

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v4

      - name: Setup PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.3'

      - name: Install dependencies
        run: composer install --no-interaction --prefer-dist

      - name: Run tests
        run: php artisan test

この例はあくまで最小構成です。実際の案件では、アプリケーションキーの生成、.env の準備、マイグレーション、Node.jsビルド、DBサービスの起動などが必要になる場合があります。

DBを使うテストで考えること

FeatureテストでDBを使う場合、CI上でどのDBを使うかを決める必要があります。SQLiteで十分なケースもありますが、本番がMySQLやPostgreSQLの場合、SQL方言や制約の違いでCIだけ通る状態になることがあります。

たとえば、外部キー制約、JSON型、日付関数、全文検索、文字コード、照合順序などはDBによって挙動が変わることがあります。業務上重要な処理をテストするなら、本番に近いDBをGitHub Actionsのサービスコンテナとして起動する選択肢もあります。

services:
  mysql:
    image: mysql:8.0
    env:
      MYSQL_DATABASE: testing
      MYSQL_ROOT_PASSWORD: password
    ports:
      - 3306:3306

DBを使うCIでは、マイグレーションをどのタイミングで流すかも重要です。php artisan migrate --force をCI内で実行し、テスト用DBを毎回同じ構造に揃えると再現性が上がります。

外部APIやメール送信はどう扱うか

テスト中に外部APIを本当に叩くと、通信失敗、レート制限、料金発生、テストデータの混入などが起きます。CIでは、外部サービスとの境界をモック、フェイク、テスト用環境に切り替えるのが基本です。

Laravelではメール、通知、キュー、ストレージなどをテスト向けに差し替えやすくなっています。CIで確認したいのは「外部サービスが本当に動くこと」ではなく、「外部サービスへ渡す直前のアプリケーション処理が正しいこと」であるケースが多いです。

CIでよく起きる失敗

ローカルでは通るのにCIでは落ちる場合、原因はコードそのものではなく環境差分であることが多いです。

  • PHP拡張がCI側に入っていない
  • .env.testing 相当の設定が足りない
  • SQLite前提のテストがMySQL前提の実装とずれている
  • タイムゾーンやロケールが違う
  • 外部APIを本当に叩いてしまっている
  • キャッシュ済み設定を読んでいる
  • npmやComposerのlockfileと実行環境がずれている

こうした失敗は、CIが悪いのではなく**「本番・開発・テスト環境の前提がコード化されていない」こと**を教えてくれます。CIで落ちた理由を一つずつ潰すことで、プロジェクトの再現性が高まります。

どこまで自動化するべきか

最初から全テスト、静的解析、E2E、デプロイまでまとめて自動化しようとすると、導入のハードルが高くなります。まずは php artisan test だけをPull Requestで実行し、落ちたらマージしない、という小さなルールから始めるのがおすすめです。

その後、必要に応じて次のように広げます。

  • composer install のキャッシュで実行時間を短縮する
  • php artisan test --parallel でテストを並列化する
  • PintやPHPStanなどの静的チェックを追加する
  • 重要画面だけブラウザテストを追加する
  • mainマージ後にデプロイワークフローへつなげる

導入時のおすすめ順序

実務では、次の順で進めると無理なく導入できます。

  1. ローカルで php artisan test が安定して通る状態にする
  2. GitHub Actionsで同じコマンドを動かす
  3. 失敗原因が環境差分ならCI設定に明示する
  4. Pull Requestで必ず実行されるようにする
  5. テスト失敗時のマージルールを決める
  6. 必要に応じて静的解析やブラウザテストを追加する

最初の目的は、網羅率を上げることではありません。変更のたびに同じ確認が走り、異常に早く気づける状態を作ることです。

まとめ

GitHub Actionsによるテスト自動化は、開発チームの安心材料になります。大切なのは、完璧なCIを最初から作ることではなく、変更のたびに同じ確認が自動で走る状態を作ることです。

小さく始めて、落ちた原因を直しながら育てていくことで、Laravelプロジェクトの保守性は少しずつ高まります。