Laravel Tdd

affaan-m/ECC/docs/ja-JP/skills/laravel-tdd

作者 affaan-mef648e01899ba3e8dc6371642deaaf64b4477775無授權條款275K 個星標收錄於 2026年10月9日更新於 2026年10月9日儲存庫4 天前更新

Laravel での TDD:PHPUnit と Pest、ファクトリー、データベーステスト、フェイク、カバレッジターゲット

AI 產生的概覽

指導 Laravel 應用程式的測試驅動開發,使用 PHPUnit 與 Pest,涵蓋工廠、資料庫策略與假物件。

功能
提供以 RED-GREEN-REFACTOR 循環為基礎的 Laravel TDD 工作流程,涵蓋單元、功能與整合測試層。內容說明 RefreshDatabase、DatabaseTransactions 等資料庫策略、工廠用法,針對工作、佇列、郵件、通知與事件的假物件,Sanctum 驗證測試、HTTP 假物件、授權斷言以及 Inertia 斷言。同時列出覆蓋率目標與測試指令,並附上 PHPUnit 與 Pest 程式碼範例。
適用情境
適用於新增 Laravel 功能或端點、修正錯誤、重構,或測試 Eloquent 模型、原則、工作與通知。適合預設採用 Pest,或已統一使用 PHPUnit 的專案。
執行需求
需要 Laravel 專案並安裝 PHPUnit 或 Pest、PHP 與 Composer 相依套件,以及測試資料庫設定(例如記憶體中的 SQLite)。覆蓋率報告使用 pcov 或 XDEBUG_MODE=coverage。不附帶指令碼,僅為說明與程式碼範例。

Laravel TDD ワークフロー

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

使用時機

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

仕組み

RED-GREEN-REFACTOR サイクル

  1. テスト失敗を書く
  2. 最小限の変更を実装して合格させる
  3. テストを緑に保ちながらリファクタリング

テスト層

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

スコープに基づいて層を選択:

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

データベース戦略

  • RefreshDatabase ほとんどのフィーチャー/統合テスト用(テスト実行ごとにマイグレーションを 1 回実行し、次に各テストをトランザクション内でラップ;メモリ内データベースは各テストごとに再マイグレーションする可能性がある)
  • DatabaseTransactions スキーマがすでにマイグレーションされており、テストごとのロールバックのみが必要なとき
  • DatabaseMigrations すべてのテストで完全な migrate/fresh が必要なとき、またはコストを負担できるとき

RefreshDatabase をデータベースに触れるテストのデフォルトとして使用:トランザクション サポート付きデータベースの場合、マイグレーション ステップ フラグを使用して テスト実行ごとに 1 回実行し、次に各テストをトランザクション内でラップします;:memory: SQLite または非トランザクションの接続では、各テストの前にマイグレーションします。スキーマがすでにマイグレーションされており、テストごとのロールバックのみが必要なときは DatabaseTransactions を使用します。

テストフレームワーク選択

  • 新しいテストの場合は Pest をデフォルトで使用。
  • PHPUnit はプロジェクトがすでにそれを標準化している、またはPHPUnit 固有のツールが必要なときのみ使用。

例

PHPUnit 例

php
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 レイヤー)

php
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 例

php
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 レイヤー)

php
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']);});

ファクトリーと状態

  • テストデータにはファクトリーを使用
  • エッジケース(アーカイブ済み、管理者、トライアル)の状態を定義
php
$user = User::factory()->state(['role' => 'admin'])->create();

データベーステスト

  • クリーンな状態には RefreshDatabase を使用
  • テストを隔離して決定論的に保つ
  • 手動クエリより assertDatabaseHas を優先

永続性テスト例

php
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() ドメインイベント用
php
use Illuminate\Support\Facades\Queue;
Queue::fake();
dispatch(new SendOrderConfirmation($order->id));
Queue::assertPushed(SendOrderConfirmation::class);
php
use Illuminate\Support\Facades\Notification;
Notification::fake();
$user->notify(new InvoiceReady($invoice));
Notification::assertSentTo($user, InvoiceReady::class);

認証テスト(Sanctum)

php
use Laravel\Sanctum\Sanctum;
Sanctum::actingAs($user);
$response = $this->getJson('/api/projects');$response->assertOk();

HTTP と外部サービス

  • Http::fake() を使用して外部 API を隔離
  • 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: を設定して高速テスト
  • テストは dev/prod データに触れないように別の env を保つ

認可テスト

php
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 テスティングヘルパーでコンポーネント名とプロップをアサート。

php
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')        );    }}

生の JSON アサーションより assertInertia を優先して、テストを Inertia レスポンスに合わせておく。

來源與署名

來源:affaan-m/ECC位於docs/ja-JP/skills/laravel-tdd提交ef648e0

授權條款: 無授權條款

內容歸原作者所有。SourceWeft 從公開儲存庫中收錄這些內容。

檢舉或申請下架