Laravel Testing ile Pest 5 (2026): TIA, Mocking ve Mülakat Soruları

Pest 5, Test Impact Analysis, Mockery, facade fake'leri ve mimari testlerle Laravel test pratiklerinde ustalaşın. Unit testler, feature testler, mocking stratejileri ve Laravel geliştiricileri için yaygın mülakat soruları.

Laravel Testing 2026 - Pest framework ile test yazma ve mocking teknikleri

Laravel test pratikleri Pest 5, TIA (Test Impact Analysis) motoru ve PHPUnit 13 ile önemli ölçüde değişmiştir. Laravel 13, Pest için birinci sınıf destek sunarak, saf PHPUnit'e kıyasla daha ifade edici ve daha az verbose bir test deneyimi sağlamaktadır. Bu rehber, hem production uygulamaları hem de teknik mülakatlar için önemli olan kalıpları kapsamaktadır.

Pest 5 Standarttır

Pest 5 (PHPUnit 13 üzerine inşa edilmiş) Laravel 13'ün varsayılan test framework'üdür. PHP 8.4+ gerektirmekte ve TIA motoru, birinci taraf AI agent doğrulaması, PHPStan entegrasyonu ve time-balanced sharding özelliklerini sunmaktadır.

Laravel 13 Projesinde Pest 5 Kurulumu

Her yeni Laravel 13 uygulaması Pest'i otomatik olarak yapılandırmaktadır. Mevcut projeler için Pest 4'ten geçiş dakikalar içinde tamamlanmaktadır, çünkü ana husus PHPUnit 13 uyumluluğudur. Yapılandırma, global trait'lerin ve yardımcı metodların kaydedildiği tests/Pest.php dosyasında yer almaktadır.

tests/Pest.phpphp
use IlluminateFoundationTestingRefreshDatabase;

pest()
    ->extend(TestsTestCase::class)
    ->use(RefreshDatabase::class)
    ->in('Feature');

Bu tek dosya, eski CreatesApplication trait'ini ve base test class kalıtımını değiştirmektedir. RefreshDatabase trait'i her testi bir veritabanı transaction'ı içine sararak değişiklikleri otomatik olarak geri almaktadır.

tests/Feature/UserRegistrationTest.phpphp
use AppModelsUser;

it('registers a new user with valid data', function () {
    $response = $this->postJson('/api/register', [
        'name' => 'Jane Doe',
        'email' => 'jane@example.com',
        'password' => 'SecurePass123!',
        'password_confirmation' => 'SecurePass123!',
    ]);

    $response->assertStatus(201)
        ->assertJsonStructure(['user' => ['id', 'name', 'email']]);

    expect(User::where('email', 'jane@example.com')->exists())->toBeTrue();
});

Pest'in expect() API'si PHPUnit assertion'ları ile doğal bir şekilde zincirlenmektedir. assertJsonStructure çağrısı yanıt yapısını doğrularken, expect()->toBeTrue() veritabanı durumunu onaylamaktadır. Her iki stil çakışmadan bir arada kullanılabilmektedir.

Test Impact Analysis: Pest 5'in Öne Çıkan Özelliği

TIA motoru, Pest 5'i büyük kod tabanları için dönüştürücü kılmaktadır. İlk çalıştırmada Pest, hangi testlerin hangi dosyalara dokunduğunu kaydeder. Sonraki her çalıştırma yalnızca değişikliklerden etkilenen testleri çalıştırır ve geri kalanlar için önbelleğe alınmış sonuçları tekrar oynatır.

bash
# First run: records baseline (requires PCOV or Xdebug)
php artisan test

# Subsequent runs: only affected tests execute
php artisan test

19.000'den fazla test içeren Laravel Cloud test suite'i, TIA etkinleştirildiğinde yaklaşık üç dakikadan beş saniyeye düşmüştür. Motor PHP dosyalarından fazlasını anlamaktadır: migration'lardaki, Blade template'lerindeki ve paylaşılan JavaScript bileşenlerindeki değişiklikleri algılamaktadır.

TIA, baseline'ı kaydetmek için bir coverage driver'ı (PCOV veya Xdebug) gerektirmektedir. CI pipeline'larında önbelleğe alınan eşlemeler çalıştırmalar arasında kalıcı olmakta, bu da performans kazancını kümülatif hale getirmektedir.

Laravel'de Unit Test vs Feature Test

Laravel'de unit ve feature testler arasındaki ayrım, framework'ün hangi bölümlerinin başlatılacağını belirlemektedir. Unit testler uygulama container'ı olmadan çalışarak daha hızlı ancak saf mantıkla sınırlı olmaktadır. Feature testler tam uygulamayı başlatarak HTTP çağrıları, veritabanı sorguları ve servis çözümlemesi sağlamaktadır.

tests/Unit/PriceCalculatorTest.phpphp
use AppServicesPriceCalculator;

describe('PriceCalculator', function () {
    it('applies a percentage discount correctly', function () {
        $calculator = new PriceCalculator();

        // 20% off a 150.00 base price
        $result = $calculator->applyDiscount(150.00, 20);

        expect($result)->toBe(120.00);
    });

    it('rejects negative discount values', function () {
        $calculator = new PriceCalculator();

        expect(fn () => $calculator->applyDiscount(100.00, -5))
            ->toThrow(InvalidArgumentException::class);
    });
});

Unit testler harici bağımlılığı olmayan izole sınıfları hedeflemektedir. describe bloğu ilgili assertion'ları gruplamakta ve Pest 5 karmaşık test hiyerarşileri için iç içe describe bloklarını desteklemektedir.

Feature testler bir Laravel test suite'inin çoğunluğunu oluşturmalıdır. Yanlış route middleware, eksik validation kuralları veya bozuk Eloquent ilişkileri gibi unit testlerin kaçırdığı entegrasyon hatalarını yakalarlar. Genel kural: kod veritabanına, HTTP katmanına veya bir facade'a dokunuyorsa, feature test yazılmalıdır.

Facade'lar ve Mockery ile Mocking Stratejileri

Laravel testlerinde mocking, test edilen kodu harici bağımlılıklardan izole etmektedir. Laravel facade'ları queue'lar, event'ler, notification'lar, mail ve storage için yerleşik fake implementasyonlar sağlamaktadır. Mockery diğer her şeyi ele almaktadır.

tests/Feature/OrderProcessingTest.phpphp
use AppModelsOrder;
use AppModelsUser;
use IlluminateSupportFacadesMail;
use IlluminateSupportFacadesQueue;
use AppMailOrderConfirmation;
use AppJobsProcessPayment;

it('dispatches payment job and sends confirmation email', function () {
    // Fake both Mail and Queue facades
    Mail::fake();
    Queue::fake();

    $user = User::factory()->create();
    $order = Order::factory()->for($user)->create([
        'total' => 99.99,
        'status' => 'pending',
    ]);

    // Act: confirm the order via HTTP
    $this->actingAs($user)
        ->postJson("/api/orders/{$order->id}/confirm")
        ->assertOk();

    // Assert: payment job was dispatched with correct amount
    Queue::assertPushed(ProcessPayment::class, function ($job) use ($order) {
        return $job->order->id === $order->id
            && $job->order->total === 99.99;
    });

    // Assert: confirmation email was sent to the user
    Mail::assertSent(OrderConfirmation::class, function ($mail) use ($user) {
        return $mail->hasTo($user->email);
    });
});

Facade fake'leri çağrıları framework seviyesinde yakalayarak gerçek e-posta gönderimini veya job dispatch'ini önlemektedir. Closure tabanlı assertion'lar her bileşene iletilen kesin verileri doğrulamaktadır.

Sınırlarda Mock Yapın

Dahili domain sınıflarını mock'lamaktan kaçının. Sınırlarda mock yapın: üçüncü taraf API'ler, mail, queue'lar, dosya sistemleri. Aşırı mocking testleri kırılgan ve implementasyon detaylarına sıkıca bağlı hale getirmektedir.

Facade olmayan bağımlılıklar için, constructor üzerinden enjekte edin ve Mockery kullanın:

tests/Feature/PaymentGatewayTest.phpphp
use AppServicesPaymentGateway;
use AppServicesStripeClient;

it('charges the customer through the payment gateway', function () {
    // Create a mock of the Stripe client
    $stripeClient = Mockery::mock(StripeClient::class);
    $stripeClient->shouldReceive('charge')
        ->once()
        ->with('cus_abc123', 5000, 'usd')
        ->andReturn(['status' => 'succeeded', 'id' => 'ch_xyz']);

    // Bind the mock in the container
    $this->app->instance(StripeClient::class, $stripeClient);

    $gateway = app(PaymentGateway::class);
    $result = $gateway->processCharge('cus_abc123', 50.00);

    expect($result['status'])->toBe('succeeded');
});

$this->app->instance() ile mock'u bağlamak, test süresince gerçek implementasyonu değiştirmektedir. Mockery, charge metodunun beklenen argümanlarla tam olarak bir kez çağrıldığını doğrulamaktadır.

Pest Preset'leri ile Mimari Testler

Pest 5, kod tabanı genelinde yapısal kuralları zorunlu kılan mimari testler içermektedir. Bu testler runtime yerine AST üzerinde çalışarak son derece hızlı olmaktadır.

tests/Architecture/ArchitectureTest.phpphp
arch('controllers do not use Eloquent directly')
    ->expect('AppHttpControllers')
    ->not->toUse('IlluminateDatabaseEloquent');

arch('services are final classes')
    ->expect('AppServices')
    ->toBeFinal();

arch('no debugging functions in production code')
    ->expect(['dd', 'dump', 'var_dump', 'ray'])
    ->not->toBeUsed();

İlk kural controller'ların veritabanını doğrudan sorgulamasını engelleyerek bir service layer pattern'i zorlamaktadır. İkincisi service'lerin extend edilemeyeceğini sağlayarak kalıtım karmaşıklığını azaltmaktadır. Üçüncüsü kalan debug ifadelerini production'a ulaşmadan önce yakalamaktadır.

Laravel'e özel preset'ler de mevcuttur:

tests/Architecture/LaravelPresetTest.phpphp
arch()->preset()->laravel();
arch()->preset()->security();
arch()->preset()->php();

Bu üç satır düzinelerce kuralı zorlamaktadır: modeller doğru base class'ı extend etmekte, controller'lar business logic içermemekte, hashing için eval() veya md5() gibi güvensiz fonksiyonlar bulunmamakta ve standart PHP konvansiyonları takip edilmektedir.

Laravel mülakatlarında başarılı olmaya hazır mısın?

İnteraktif simülatörler, flashcards ve teknik testlerle pratik yap.

Test Kalitesini Doğrulamak için Mutation Testing

Code coverage testler sırasında hangi satırların çalıştırıldığını ölçmektedir. Mutation testing daha ileri giderek kaynak kodu değiştirir ve testlerin değişikliği algılayıp algılamadığını kontrol eder. Bir mutasyon hayatta kalırsa, test suite'inde bir boşluk vardır.

bash
# Run mutation testing on a specific class
php artisan test --mutate --class=App\Services\PriceCalculator

Pest 5, > yerine >= koyma, return ifadelerini kaldırma ve boolean koşulları tersine çevirme gibi mutasyonlar tanıtmaktadır. %80'in altında bir mutation score genellikle testlerin edge case'leri kontrol etmeden çıktıları doğruladığını göstermektedir.

php
// Example: this test has high coverage but low mutation score
it('calculates shipping cost', function () {
    $cost = calculateShipping(weight: 5.0, zone: 'domestic');

    // Only checks that the result is numeric
    expect($cost)->toBeFloat();
});

// Improved: catches mutations by asserting the exact value
it('calculates domestic shipping for 5kg package', function () {
    $cost = calculateShipping(weight: 5.0, zone: 'domestic');

    // Exact assertion catches operator and value mutations
    expect($cost)->toBe(12.50);
});

İlk test, hesaplama mantığı tamamen yanlış olsa bile, float döndürdüğü sürece geçmektedir. İkinci test ise bir mutasyon formülü değiştirdiğinde hemen başarısız olmaktadır. Spesifik assertion'lar daha yüksek mutation score'ları üretmektedir.

Veritabanı Test Kalıpları ve Factory'ler

Laravel model factory'leri manuel array oluşturma olmadan gerçekçi test verileri üretmektedir. Pest 5 factory'lerle birleştiğinde okunabilir, bakımı kolay veri kurulumu sağlamaktadır.

tests/Feature/ArticlePublishingTest.phpphp
use AppModelsArticle;
use AppModelsUser;

it('publishes a draft article and updates the timestamp', function () {
    $author = User::factory()->create(['role' => 'editor']);

    $article = Article::factory()
        ->for($author, 'author')
        ->draft()
        ->create(['title' => 'Testing Best Practices']);

    $this->actingAs($author)
        ->patchJson("/api/articles/{$article->id}/publish")
        ->assertOk()
        ->assertJsonPath('data.status', 'published');

    $article->refresh();

    expect($article->status)->toBe('published')
        ->and($article->published_at)->not->toBeNull()
        ->and($article->published_at->isToday())->toBeTrue();
});

draft() factory state'i yayınlanmamış makaleler için varsayılan değerleri ayarlamaktadır. ->and() ile zincirlenen expect() assertion'ları doğal dil gibi okunmakta ve açıklayıcı mesajlarla başarısız olmaktadır.

Paralel Test ve Sharding

Testleri birden fazla process'te çalıştırmak için php artisan test --parallel komutunu çalıştırın. Laravel her process için otomatik olarak ayrı test veritabanları oluşturarak veri çakışmalarını önlemektedir. Pest 5'in time-balanced sharding'i testleri sayı yerine gerçek çalışma süresine göre dağıtarak her CI shard'ının aynı anda bitmesini sağlamaktadır.

Yaygın Laravel Test Mülakat Soruları

Laravel pozisyonları için teknik mülakatlar sıklıkla test bilgisini sorgular. İşte en sık karşılaşılan sorular ve güçlü bir cevabın neleri kapsaması gerektiği.

Laravel testlerinde fake(), mock() ve spy() arasındaki fark nedir?

Facade fake() tüm facade'ı bellek içi bir implementasyonla değiştirir (Mail::fake, Queue::fake). Mockery üzerinden mock() çalışmadan önce beklentiler belirler ve bunlar karşılanmazsa başarısız olur. spy() etkileşimleri kaydeder ve önceden beklenti belirlemeden çalışmadan sonra assertion yapılmasına izin verir. Seçim, testin davranışı doğrulaması (mock), etkileşimleri kaydetmesi (spy) veya yan etkileri önlemesi (fake) gerekip gerekmediğine bağlıdır.

RefreshDatabase ile DatabaseTransactions nasıl farklılık gösterir?

RefreshDatabase migration'ları bir kez çalıştırır ve her testi bir transaction'a sarar. DatabaseTransactions veritabanının zaten doğru şemaya sahip olduğunu varsayar ve yalnızca testleri transaction'lara sarar. RefreshDatabase veritabanının henüz mevcut olmayabileceği CI pipeline'ları için daha güvenlidir. DatabaseTransactions şemanın güncel olması garantiyken daha hızlıdır.

Feature testler unit testlere ne zaman tercih edilmelidir?

Feature testler HTTP katmanı, veritabanı veya Laravel servisleriyle etkileşen her kodu kapsamalıdır. Unit testler framework bağımlılığı olmayan saf fonksiyonlar ve value object'ler için ayrılmıştır. Tipik bir Laravel uygulamasında feature testler unit testleri yaklaşık 3:1 veya daha yüksek bir oranla geçmektedir. Bu, Laravel kodunun çoğunun doğası gereği framework ile entegre olduğu gerçeğini yansıtmaktadır.

Test Impact Analysis CI performansını nasıl iyileştirir?

TIA ilk çalıştırmada hangi testlerin hangi kaynak dosyalara dokunduğunu kaydeder. Sonraki çalıştırmalarda Pest yalnızca değiştirilen dosyalardan etkilenen testleri çalıştırır ve değişmeyen testler için önbelleğe alınmış sonuçları tekrar oynatır. Dakikalar süren büyük suite'ler saniyeler içinde tamamlanabilir. Değiş tokuş: TIA bağımlılık haritasını oluşturmak için bir coverage driver'ı (PCOV veya Xdebug) gerektirir ve ilk çalıştırma normal çalıştırmadan daha uzun sürer.

Mutation testing, code coverage'ın ötesinde test kalitesini nasıl iyileştirir?

Code coverage çalışma yollarını ölçer. Bir test her metodu çağırarak anlamlı bir şey assert etmeden %100 coverage'a ulaşabilir. Mutation testing kaynak kodu değiştirir (operatörleri değiştirme, return'leri kaldırma, boolean'ları tersine çevirme) ve en az bir testin başarısız olduğunu doğrular. Hayatta kalan mutasyonlar çok gevşek veya tamamen eksik assertion'ları ortaya koyar. php artisan test --mutate çalıştırmak standart coverage'ın yanında bir mutation score yüzdesi üretir.

Daha fazla Laravel mülakat sorusu için SharpSkill soru bankası authentication, service container pattern'leri, Eloquent ilişkileri ve queue mimarisini kapsamaktadır.

HTTP Yanıtlarını ve JSON Assertion'larını Test Etme

Laravel'in HTTP test helper'ları status code'ları, header'ları, JSON yapılarını ve redirect hedeflerini doğrulamaktadır. Pest ile birleştirildiğinde özlü entegrasyon testleri oluşturmaktadır.

tests/Feature/ApiAuthenticationTest.phpphp
use AppModelsUser;

describe('API Authentication', function () {
    it('rejects unauthenticated requests with 401', function () {
        $this->getJson('/api/profile')
            ->assertUnauthorized();
    });

    it('returns the authenticated user profile', function () {
        $user = User::factory()->create([
            'name' => 'John Doe',
            'email' => 'john@example.com',
        ]);

        $this->actingAs($user)
            ->getJson('/api/profile')
            ->assertOk()
            ->assertJson([
                'data' => [
                    'name' => 'John Doe',
                    'email' => 'john@example.com',
                ],
            ]);
    });

    it('validates required fields on registration', function () {
        $this->postJson('/api/register', [])
            ->assertUnprocessable()
            ->assertJsonValidationErrors(['name', 'email', 'password']);
    });
});

describe bloğu authentication ile ilgili testleri gruplamaktadır. Her test adı implementasyonu değil beklenen davranışı tanımlamaktadır. assertJsonValidationErrors metodu belirli alanların validation hata mesajlarına sahip olup olmadığını kontrol etmektedir.

Kaynaklar

Pest 5 ile Laravel Testinde Hatırlanması Gerekenler

  • Laravel 13 ile Pest 5, akıcı yapılandırma API'si, expect() zincirleri ve otomatik test keşfi sayesinde boilerplate'i ortadan kaldırmaktadır
  • TIA motoru yalnızca etkilenen testleri yeniden çalıştırarak büyük suite çalışmasını dakikalardan saniyelere düşürürken coverage doğruluğundan ödün vermemektedir
  • Feature testler Laravel test suite'inin çekirdeğini oluşturmalı, unit testler izole business logic için ayrılmalıdır
  • Facade fake'leri (Mail::fake(), Queue::fake()) framework seviyesinde mocking'i yönetirken, Mockery container üzerinden enjekte edilen üçüncü taraf bağımlılıklarını yönetmektedir
  • Mimari testler yapısal kuralları (controller'larda Eloquent yok, debug fonksiyonları yok) runtime yükü olmadan zorlamaktadır
  • --mutate ile mutation testing, code coverage'ın tek başına kaçırdığı zayıf assertion'ları yakalamaktadır
  • Factory state'leri ve zincirlenen expect()->and() assertion'ları test verisi kurulumunu okunabilir ve assertion'ları spesifik tutmaktadır
  • Laravel mülakat hazırlığı için mock/fake/spy, RefreshDatabase davranışı, TIA ve mutation testing anlayışı, temel coverage'ın ötesinde test olgunluğunu göstermektedir

Pratik yapmaya başla!

Mülakat simülatörleri ve teknik testlerle bilgini test et.

Günün meydan okuması

Laravel kodundaki hatayı bulabilir misin?

Gerçek bir kod parçası, gizli bir hata, günde bir deneme. Denemek için hesap gerekmez.

Anthony Fillion-Maillet

Yazan:

Anthony Fillion-Maillet

SharpSkill kurucusu

10 yılı aşkın süredir fullstack geliştirici. SharpSkill’i yönetiyor ve burada yayımlanan her şeyden sorumlu.

2 Eylül 2026 tarihinde güncellendi

Etiketler

#laravel
#testing
#pest
#php
#interview

Paylaş

İlgili makaleler