Everything-claude-code laravel-tdd
Test-driven development for Laravel with PHPUnit and Pest, factories, database testing, fakes, and coverage targets.
install
source · Clone the upstream repo
git clone https://github.com/affaan-m/everything-claude-code
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/affaan-m/everything-claude-code "$T" && mkdir -p ~/.claude/skills && cp -r "$T/docs/tr/skills/laravel-tdd" ~/.claude/skills/affaan-m-everything-claude-code-laravel-tdd && rm -rf "$T"
manifest:
docs/tr/skills/laravel-tdd/SKILL.mdsource content
Laravel TDD İş Akışı
80%+ kapsam (unit + feature) ile Laravel uygulamaları için test-driven development.
Ne Zaman Kullanılır
- Laravel'de yeni özellikler veya endpoint'ler
- Bug düzeltmeleri veya refactoring'ler
- Eloquent model'leri, policy'leri, job'ları ve notification'ları test etme
- Proje zaten PHPUnit'te standartlaşmamışsa yeni testler için Pest'i tercih edin
Nasıl Çalışır
Red-Green-Refactor Döngüsü
- Başarısız bir test yazın
- Geçmek için minimal değişiklik uygulayın
- Testleri yeşil tutarken refactor edin
Test Katmanları
- Unit: saf PHP sınıfları, value object'leri, servisler
- Feature: HTTP endpoint'leri, auth, validation, policy'ler
- Integration: database + kuyruk + harici sınırlar
Kapsama göre katmanları seçin:
- Saf iş mantığı ve servisler için Unit testleri kullanın.
- HTTP, auth, validation ve yanıt şekli için Feature testleri kullanın.
- DB/kuyruklar/harici servisleri birlikte doğrularken Integration testleri kullanın.
Database Stratejisi
- Çoğu feature/integration testi için
(test run'ı başına bir kez migration'ları çalıştırır, ardından desteklendiğinde her testi bir transaction'a sarar; in-memory veritabanları test başına yeniden migrate edebilir)RefreshDatabase - Şema zaten migrate edilmişse ve sadece test başına rollback'e ihtiyacınız varsa
DatabaseTransactions - Her test için tam bir migrate/fresh'e ihtiyacınız varsa ve maliyetini karşılayabiliyorsanız
DatabaseMigrations
Veritabanına dokunan testler için varsayılan olarak
RefreshDatabase kullanın: transaction desteği olan veritabanları için, test run'ı başına bir kez (static bir bayrak aracılığıyla) migration'ları çalıştırır ve her testi bir transaction'a sarar; :memory: SQLite veya transaction'sız bağlantılar için her testten önce migrate eder. Şema zaten migrate edilmişse ve sadece test başına rollback'lere ihtiyacınız varsa DatabaseTransactions kullanın.
Test Framework Seçimi
- Mevcut olduğunda yeni testler için varsayılan olarak Pest kullanın.
- Proje zaten PHPUnit'te standartlaşmışsa veya PHPUnit'e özgü araçlar gerektiriyorsa sadece PHPUnit kullanın.
Örnekler
PHPUnit Örneği
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']); } }
Feature Test Örneği (HTTP Katmanı)
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 Örneği
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']); });
Feature Test Pest Örneği (HTTP Katmanı)
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']); });
Factory'ler ve State'ler
- Test verileri için factory'leri kullanın
- Uç durumlar için state'leri tanımlayın (archived, admin, trial)
$user = User::factory()->state(['role' => 'admin'])->create();
Database Testi
- Temiz durum için
kullanınRefreshDatabase - Testleri izole ve deterministik tutun
- Manuel sorgular yerine
tercih edinassertDatabaseHas
Persistence Test Örneği
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); } }
Yan Etkiler için Fake'ler
- Job'lar için
Bus::fake() - Kuyruğa alınmış işler için
Queue::fake() - Bildirimler için
veMail::fake()Notification::fake() - Domain event'leri için
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);
Auth Testi (Sanctum)
use Laravel\Sanctum\Sanctum; Sanctum::actingAs($user); $response = $this->getJson('/api/projects'); $response->assertOk();
HTTP ve Harici Servisler
- Harici API'leri izole etmek için
kullanınHttp::fake() - Giden payload'ları
ile doğrulayınHttp::assertSent()
Kapsam Hedefleri
- Unit + feature testleri için 80%+ kapsam zorlayın
- CI'da
veyapcov
kullanınXDEBUG_MODE=coverage
Test Komutları
php artisan testvendor/bin/phpunitvendor/bin/pest
Test Yapılandırması
- Hızlı testler için
'dephpunit.xml
veDB_CONNECTION=sqlite
ayarlayınDB_DATABASE=:memory: - Dev/prod verilerine dokunmaktan kaçınmak için testler için ayrı env tutun
Yetkilendirme Testleri
use Illuminate\Support\Facades\Gate; $this->assertTrue(Gate::forUser($user)->allows('update', $project)); $this->assertFalse(Gate::forUser($otherUser)->allows('update', $project));
Inertia Feature Testleri
Inertia.js kullanırken, Inertia test yardımcıları ile component ismi ve prop'ları doğrulayın.
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') ); } }
Testleri Inertia yanıtlarıyla uyumlu tutmak için ham JSON assertion'ları yerine
assertInertia tercih edin.