laravel-tdd

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Test-Driven Development for Laravel

Laravel的测试驱动开发

Overview

概述

Write the test first. Watch it fail. Write minimal code to pass.
This skill adapts TDD principles specifically for Laravel applications using Pest PHP, Laravel's testing features, and framework-specific patterns.
先编写测试。观察测试失败。再编写最少的代码使测试通过。
本技能针对使用Pest PHP、Laravel测试功能及框架特定模式的Laravel应用程序,适配了TDD原则。

When to Use

使用场景

Always for Laravel:
  • New features (controllers, models, services)
  • Bug fixes
  • API endpoints
  • Database migrations and models
  • Form validation
  • Authorization policies
  • Queue jobs
  • Artisan commands
  • Middleware
Exceptions (ask your human partner):
  • Throwaway prototypes
  • Configuration files
  • View-only changes (no logic)
Laravel开发必用:
  • 新功能(控制器、模型、服务)
  • Bug修复
  • API端点
  • 数据库迁移与模型
  • 表单验证
  • 授权策略
  • 队列任务
  • Artisan命令
  • 中间件
例外情况(请咨询你的协作人员):
  • 一次性原型
  • 配置文件
  • 仅视图修改(无逻辑)

The Laravel TDD Cycle

Laravel的TDD循环

RED → Verify RED → GREEN → Verify GREEN → REFACTOR → Repeat
RED → 验证RED → GREEN → 验证GREEN → REFACTOR → 重复

RED - Write Failing Test

RED - 编写失败的测试

Write one minimal test showing what the Laravel feature should do.
Feature Test Example:
php
<?php

use App\Models\User;
use App\Models\Post;

test('authenticated user can create post', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user)
        ->post('/posts', [
            'title' => 'My First Post',
            'content' => 'Post content here',
        ])
        ->assertRedirect('/posts');
    
    expect(Post::where('title', 'My First Post')->exists())->toBeTrue();
    expect(Post::first()->user_id)->toBe($user->id);
});
编写一个最简化的测试,明确Laravel功能应实现的效果。
功能测试示例:
php
<?php

use App\Models\User;
use App\Models\Post;

test('authenticated user can create post', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user)
        ->post('/posts', [
            'title' => 'My First Post',
            'content' => 'Post content here',
        ])
        ->assertRedirect('/posts');
    
    expect(Post::where('title', 'My First Post')->exists())->toBeTrue();
    expect(Post::first()->user_id)->toBe($user->id);
});

Verify RED - Watch It Fail

验证RED - 观察测试失败

bash
php artisan test --filter=authenticated_user_can_create_post
bash
php artisan test --filter=authenticated_user_can_create_post

GREEN - Minimal Laravel Code

GREEN - 编写最简Laravel代码

Write simplest Laravel code to pass the test.
编写最简单的Laravel代码使测试通过。

Verify GREEN - Watch It Pass

验证GREEN - 观察测试通过

bash
php artisan test
bash
php artisan test

REFACTOR - Clean Up Laravel Code

REFACTOR - 优化Laravel代码

After green only:
  • Extract services for complex logic
  • Create policies for authorization
  • Add query scopes for reusability
  • Use events for side effects
仅在测试通过后进行:
  • 为复杂逻辑提取服务
  • 创建授权策略
  • 添加可复用的查询作用域
  • 使用事件处理副作用

Laravel-Specific Test Patterns

Laravel专属测试模式

Database Testing

数据库测试

php
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('creates post in database', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user)
        ->post('/posts', ['title' => 'Test', 'content' => 'Content']);
    
    $this->assertDatabaseHas('posts', ['title' => 'Test']);
});
php
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

test('creates post in database', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user)
        ->post('/posts', ['title' => 'Test', 'content' => 'Content']);
    
    $this->assertDatabaseHas('posts', ['title' => 'Test']);
});

Authorization Testing

授权测试

php
test('user cannot delete others posts', function () {
    $user = User::factory()->create();
    $post = Post::factory()->create();
    
    $this->actingAs($user)
        ->delete("/posts/{$post->id}")
        ->assertForbidden();
});
php
test('user cannot delete others posts', function () {
    $user = User::factory()->create();
    $post = Post::factory()->create();
    
    $this->actingAs($user)
        ->delete("/posts/{$post->id}")
        ->assertForbidden();
});

API Testing

API测试

php
test('creates post via API', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user, 'sanctum')
        ->postJson('/api/posts', ['title' => 'API Post', 'content' => 'Content'])
        ->assertCreated();
});
php
test('creates post via API', function () {
    $user = User::factory()->create();
    
    $this->actingAs($user, 'sanctum')
        ->postJson('/api/posts', ['title' => 'API Post', 'content' => 'Content'])
        ->assertCreated();
});

Verification Checklist

验证检查清单

  • Migration test passes
  • Model relationships tested
  • Controller actions tested
  • Validation rules tested
  • Authorization tested
  • Database state verified
  • All tests passing
  • Used RefreshDatabase
  • Used factories
  • 迁移测试通过
  • 模型关联已测试
  • 控制器动作已测试
  • 验证规则已测试
  • 授权已测试
  • 数据库状态已验证
  • 所有测试通过
  • 使用了RefreshDatabase
  • 使用了工厂

Remember

谨记

Every Laravel feature → Test exists and failed first
Otherwise → Not TDD
每个Laravel功能 → 先编写测试并确保其失败
否则 → 不属于TDD