Laravel test yazmak, bir projeyi “çalışıyor gibi görünen” kod yığınından, üzerinde gönül rahatlığıyla değişiklik yapabileceğin sağlam bir kod tabanına dönüştüren en önemli alışkanlıktır. Testler, refactor sırasında hangi davranışı bozduğunu sana anında söyler; yeni gelen bir geliştirici için canlı dokümantasyon görevi görür; ve en önemlisi, her dağıtımda “acaba bir yeri kırdım mı?” stresini ortadan kaldırır. Bu rehberde Laravel'in iki test motorunu — varsayılan PHPUnit ve daha sade söz dizimiyle popülerleşen Pest — pratik örneklerle ele alacağız.
Laravel'de test altyapısı nasıl kurulu?
Yeni bir Laravel projesi zaten testle gelir. Kök dizindeki phpunit.xml dosyası test ortamını tanımlar, tests/ klasörü ise iki alt dizine ayrılır: tests/Unit ve tests/Feature. Ayrım kavramsaldır:
- Unit testleri tek bir sınıfı ya da metodu, Laravel'i ayağa kaldırmadan, izole biçimde sınar. Hızlıdırlar ve saf mantığa (hesaplama, biçimlendirme, küçük servisler) odaklanırlar.
- Feature testleri bir HTTP isteği, bir route, veritabanı ve birden çok sınıfın birlikte çalışmasını uçtan uca sınar. Gerçek dünyada en çok değer üreten testler bunlardır.
Testleri çalıştırmak için en pratik komut Laravel'in kendi sarmalayıcısıdır:
php artisan test
# veya doğrudan:
./vendor/bin/phpunit
# tek bir testi süzmek için:
php artisan test --filter=ProjectCanBeCreated
phpunit.xml içinde test ortamı genelde APP_ENV=testing ve bellekte çalışan bir SQLite (DB_CONNECTION=sqlite, DB_DATABASE=:memory:) ile ayarlanır. Böylece testler gerçek veritabanına dokunmadan, her seferinde temiz bir şemayla çalışır.
İlk feature testini yazmak
Bir test sınıfı oluşturmak için artisan yeterli:
php artisan make:test ProjectTest # tests/Feature
php artisan make:test PriceTest --unit # tests/Unit
Basit bir feature testi, bir sayfanın doğru yüklenip yüklenmediğini doğrulamakla başlar. PHPUnit söz dizimiyle:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
class ProjectTest extends TestCase
{
use RefreshDatabase;
public function test_anasayfa_basariyla_yuklenir(): void
{
$response = $this->get('/');
$response->assertStatus(200);
$response->assertSee('Aslain');
}
}
Burada $this->get('/') gerçek bir HTTP isteği taklit eder; assertStatus ve assertSee ise yanıtı doğrular. Test metodu adının test_ ile başlaması (ya da #[Test] öznitelikiyle işaretlenmesi) PHPUnit'in onu tanıması için gerekir.
Veritabanı testleri ve RefreshDatabase
Veritabanına dokunan testlerde RefreshDatabase trait'i kritiktir: her testten önce şemayı bir transaction içinde sıfırlar, test bitince geri alır. Böylece testler birbirini etkilemez. Veri üretmek için ise factory'ler kullanılır:
public function test_proje_veritabanina_kaydedilir(): void
{
$project = Project::factory()->create([
'title' => ['tr' => 'Test Projesi'],
]);
$this->assertDatabaseHas('projects', [
'id' => $project->id,
]);
}
assertDatabaseHas tablodaki bir satırı doğrudan sorgular. Karşıtı assertDatabaseMissing, silme işlemlerini test ederken işine yarar. Factory'ler database/factories altında tanımlanır ve fake() yardımcısıyla gerçekçi rastgele veri üretir.
Kimlik doğrulama, JSON ve form gönderimi
Gerçek uygulamalarda çoğu route giriş yapmış kullanıcı ister. Laravel bunu actingAs ile tek satırda halleder:
public function test_yetkili_kullanici_proje_ekleyebilir(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/admin/projects', [
'title_tr' => 'Yeni Proje',
]);
$response->assertRedirect('/admin/projects');
$this->assertDatabaseHas('projects', ['title->tr' => 'Yeni Proje']);
}
JSON tabanlı API'ler için ise getJson, postJson gibi metotlar ve yapı doğrulayan assertJson / assertJsonStructure vardır:
$this->getJson('/api/projects')
->assertOk()
->assertJsonCount(3, 'data')
->assertJsonStructure(['data' => [['id', 'title']]]);
Pest ile aynı testleri daha sade yazmak
Pest, PHPUnit'in üzerine kurulu bir test çatısıdır; yani altyapı aynı, söz dizimi daha akıcıdır. Sınıf ve metot yerine fonksiyon temelli yazarsın. Aynı feature testi Pest'te şöyle görünür:
<?php
use App\Models\User;
it('yetkili kullanicinin proje eklemesine izin verir', function () {
$user = User::factory()->create();
$this->actingAs($user)
->post('/admin/projects', ['title_tr' => 'Yeni Proje'])
->assertRedirect('/admin/projects');
expect(Project::count())->toBe(1);
});
expect() ifadesi okunabilir bir doğrulama zinciri (toBe, toBeTrue, toContain…) sunar. RefreshDatabase gibi trait'ler ise tests/Pest.php dosyasında uses() ile bir dizine topluca uygulanır. Pest'i kurmak için projeye pestphp/pest paketini Composer ile ekleyip php artisan pest:install çalıştırman yeterlidir; mevcut PHPUnit testlerin bozulmadan yan yana çalışmaya devam eder.
Bağımlılıkları taklit etmek: mock ve fake'ler
İyi testler dış servislere (e-posta, ödeme, bildirim) gerçekten bağlanmaz. Laravel bunun için hazır fake'ler sunar. Örneğin bir bildirim gönderildiğini, gerçek e-posta atmadan doğrulayabilirsin:
use Illuminate\Support\Facades\Mail;
Mail::fake();
// ... eylem ...
Mail::assertSent(WelcomeMail::class);
Aynı mantık Queue::fake(), Event::fake(), Storage::fake() ve Http::fake() için de geçerlidir. Bunlar testleri hem hızlı hem de deterministik tutar — internet bağlantısına veya üçüncü taraf servisin durumuna bağlı kalmazlar.
Sık Sorulan Sorular
PHPUnit mi Pest mi seçmeliyim?
İkisi de aynı motoru kullanır, dolayısıyla teknik bir üstünlük yarışı değildir. Sınıf temelli, kurumsal ve tanıdık bir yapı istiyorsan PHPUnit; daha az şablon kod ve okunabilir söz dizimi istiyorsan Pest mantıklı. Yeni projelerde Pest giderek varsayılan tercih hâline geliyor, ama ekibinin alışkanlığı belirleyici olmalı.
Her şeyi mi test etmeliyim?
Hayır. %100 kapsam (coverage) hedefi genelde verimsizdir. Önce iş açısından kritik akışları (ödeme, kayıt, yetkilendirme, sipariş) ve geçmişte bozulmuş yerleri test et. Saf getter/setter veya framework'ün kendi kodu için test yazmak zaman kaybıdır.
Testler neden yavaş çalışıyor?
En sık neden, bellekte SQLite yerine gerçek veritabanına gidilmesi ve dış servislerin fake'lenmemesidir. :memory: SQLite, RefreshDatabase ve uygun fake'lerle bir test paketi saniyeler içinde çalışabilir.
Test yazmayı projene yerleştirmek mi istiyorsun? Mevcut Laravel uygulamana güvenli bir test paketi kurmaktan CI/CD entegrasyonuna kadar yardıma ihtiyacın olursa benimle iletişime geç — kod tabanını birlikte sağlamlaştıralım.