本文へ移動
cccskills
無料GitHub で公開

laravel-tdd

PHPUnitとPestによるLaravelのテスト駆動開発、ファクトリー、データベーステスト、フェイク、カバレッジ目標。

インストール方法を見る

含まれるファイル(1)

  • SKILL.md8.6 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Laravel TDDワークフロー

PHPUnitとPestを使用した80%以上のカバレッジ(ユニット + フィーチャー)によるLaravelアプリケーションのテスト駆動開発。

使用タイミング

  • Laravelでの新機能やエンドポイント
  • バグ修正やリファクタリング
  • Eloquentモデル、ポリシー、ジョブ、通知のテスト
  • プロジェクトが既にPHPUnitを標準化していない限り、新しいテストにはPestを優先

仕組み

Red-Green-Refactorサイクル

  1. 失敗するテストを書く
  2. テストを通過する最小限の変更を実装
  3. テストをグリーンに保ちながらリファクタリング

テストレイヤー

  • ユニット: 純粋なPHPクラス、値オブジェクト、サービス
  • フィーチャー: HTTPエンドポイント、認証、バリデーション、ポリシー
  • インテグレーション: データベース + キュー + 外部境界

スコープに基づいてレイヤーを選択:

  • 純粋なビジネスロジックとサービスにはユニットテストを使用。
  • HTTP、認証、バリデーション、レスポンス形状にはフィーチャーテストを使用。
  • DB/キュー/外部サービスを一緒に検証する場合はインテグレーションテストを使用。

データベース戦略

  • ほとんどのフィーチャー/インテグレーションテストにはRefreshDatabase(テスト実行ごとに1回マイグレーションを実行し、サポートされている場合は各テストをトランザクションでラップ。インメモリデータベースではテストごとに再マイグレーションする場合あり)
  • スキーマが既にマイグレーション済みでテストごとのロールバックのみが必要な場合はDatabaseTransactions
  • テストごとに完全なmigrate/freshが必要でそのコストを許容できる場合はDatabaseMigrations

データベースに触れるテストにはデフォルトでRefreshDatabaseを使用: トランザクションサポートのあるデータベースでは、テスト実行ごとに1回マイグレーションを実行し(静的フラグを使用)、各テストをトランザクションでラップ。:memory: SQLiteやトランザクションのないコネクションでは、各テスト前にマイグレーション。スキーマが既にマイグレーション済みでテストごとのロールバックのみが必要な場合はDatabaseTransactionsを使用。

テスティングフレームワークの選択

  • 利用可能な場合は新しいテストにPestをデフォルトで使用。
  • プロジェクトが既にPHPUnitを標準化しているか、PHPUnit固有のツーリングが必要な場合にのみPHPUnitを使用。

事例

PHPUnitの例

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

final class ProjectControllerTest extends TestCase
{
    use RefreshDatabase;

    public function test_owner_can_create_project(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->postJson('/api/projects', [
            'name' => 'New Project',
        ]);

        $response->assertCreated();
        $this->assertDatabaseHas('projects', ['name' => 'New Project']);
    }
}

フィーチャーテストの例(HTTPレイヤー)

use App\Models\Project;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

final class ProjectIndexTest extends TestCase
{
    use RefreshDatabase;

    public function test_projects_index_returns_paginated_results(): void
    {
        $user = User::factory()->create();
        Project::factory()->count(3)->for($user)->create();

        $response = $this->actingAs($user)->getJson('/api/projects');

        $response->assertOk();
        $response->assertJsonStructure(['success', 'data', 'error', 'meta']);
    }
}

Pestの例

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

use function Pest\Laravel\actingAs;
use function Pest\Laravel\assertDatabaseHas;

uses(RefreshDatabase::class);

test('owner can create project', function () {
    $user = User::factory()->create();

    $response = actingAs($user)->postJson('/api/projects', [
        'name' => 'New Project',
    ]);

    $response->assertCreated();
    assertDatabaseHas('projects', ['name' => 'New Project']);
});

フィーチャーテストPestの例(HTTPレイヤー)

use App\Models\Project;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

use function Pest\Laravel\actingAs;

uses(RefreshDatabase::class);

test('projects index returns paginated results', function () {
    $user = User::factory()->create();
    Project::factory()->count(3)->for($user)->create();

    $response = actingAs($user)->getJson('/api/projects');

    $response->assertOk();
    $response->assertJsonStructure(['success', 'data', 'error', 'meta']);
});

ファクトリーとステート

  • テストデータにはファクトリーを使用
  • エッジケース用にステートを定義(archived、admin、trial)
$user = User::factory()->state(['role' => 'admin'])->create();

データベーステスト

  • クリーンな状態のためにRefreshDatabaseを使用
  • テストを分離し決定的に保つ
  • 手動クエリよりassertDatabaseHasを優先

永続化テストの例

use App\Models\Project;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

final class ProjectRepositoryTest extends TestCase
{
    use RefreshDatabase;

    public function test_project_can_be_retrieved_by_slug(): void
    {
        $project = Project::factory()->create(['slug' => 'alpha']);

        $found = Project::query()->where('slug', 'alpha')->firstOrFail();

        $this->assertSame($project->id, $found->id);
    }
}

副作用のためのフェイク

  • ジョブにはBus::fake()
  • キューイングされた処理にはQueue::fake()
  • 通知にはMail::fake()とNotification::fake()
  • ドメインイベントにはEvent::fake()
use Illuminate\Support\Facades\Queue;

Queue::fake();

dispatch(new SendOrderConfirmation($order->id));

Queue::assertPushed(SendOrderConfirmation::class);
use Illuminate\Support\Facades\Notification;

Notification::fake();

$user->notify(new InvoiceReady($invoice));

Notification::assertSentTo($user, InvoiceReady::class);

認証テスト(Sanctum)

use Laravel\Sanctum\Sanctum;

Sanctum::actingAs($user);

$response = $this->getJson('/api/projects');
$response->assertOk();

HTTPと外部サービス

  • 外部APIを分離するためにHttp::fake()を使用
  • Http::assertSent()でアウトバウンドペイロードをアサート

カバレッジ目標

  • ユニット + フィーチャーテストで80%以上のカバレッジを適用
  • CIではpcovまたはXDEBUG_MODE=coverageを使用

テストコマンド

  • php artisan test
  • vendor/bin/phpunit
  • vendor/bin/pest

テスト設定

  • phpunit.xmlでDB_CONNECTION=sqliteとDB_DATABASE=:memory:を設定して高速テスト
  • 開発/本番データに触れないようテスト用に別の環境を保持

認可テスト

use Illuminate\Support\Facades\Gate;

$this->assertTrue(Gate::forUser($user)->allows('update', $project));
$this->assertFalse(Gate::forUser($otherUser)->allows('update', $project));

Inertiaフィーチャーテスト

Inertia.jsを使用する場合、Inertiaテストヘルパーでコンポーネント名とpropsをアサート。

use App\Models\User;
use Inertia\Testing\AssertableInertia;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

final class DashboardInertiaTest extends TestCase
{
    use RefreshDatabase;

    public function test_dashboard_inertia_props(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->get('/dashboard');

        $response->assertOk();
        $response->assertInertia(fn (AssertableInertia $page) => $page
            ->component('Dashboard')
            ->where('user.id', $user->id)
            ->has('projects')
        );
    }
}

Inertiaレスポンスに合わせてテストを保つため、生のJSONアサーションよりassertInertiaを優先してください。

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

agent-eval

無料日本語概要

コーディングエージェント(Claude Code、Aider、Codexなど)のカスタムタスクによる直接比較。合格率、コスト、時間、一貫性メトリクスを測定

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

agent-harness-construction

無料日本語概要

AIエージェントのアクションスペース、ツール定義、オブザベーションフォーマットを設計・最適化し、タスク完了率を向上させる

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

agentic-engineering

無料日本語概要

評価ファーストの実行、分解、コスト考慮型モデルルーティングによるエージェンティックエンジニアとしての運用

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

ai-first-engineering

無料日本語概要

AIエージェントが実装出力の大部分を生成するチームのためのエンジニアリング運用モデル

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

ai-regression-testing

無料日本語概要

AI支援開発のためのリグレッションテスト戦略。データベース依存なしのサンドボックスモードAPIテスト、自動バグチェックワークフロー、同一モデルがコードの作成とレビューを行う際のAIの盲点を検出するパターン。

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

android-clean-architecture

無料日本語概要

AndroidおよびKotlin Multiplatformプロジェクトのためのクリーンアーキテクチャパターン — モジュール構成、依存関係ルール、UseCase、Repository、データレイヤーパターン

hage-oyaji/everything-claude-code-jp-local32026年3月29日 更新

hage-oyaji のスキルをすべて見る

このスキルの問題を報告する