# Laravel'de test yazma alışkanlığı: Pest'e geçiş

> PHPUnit'ten Pest'e geçerken test yazmayı külfetten alışkanlığa çeviren sözdizimi ve yapı farklarını anlatıyorum.

- Yayın: 2021-09-05
- Kategori: Araçlar & Teknolojiler
- Etiketler: Laravel, Test
- Okuma süresi: 3 dk okuma
- Kaynak: https://www.muhammetsafak.com.tr/blog/laravelde-test-yazma-aliskanligi-peste-gecis/
- Dil: tr-TR
- Yazar: Muhammet Şafak

---
Test yazmak iyi bir fikir olduğunu biliyordum; ama bir süre boyunca "yazmalıyım" ile "yazıyorum" arasındaki mesafeyi kapatamadım. [PHPUnit'i öğrenmek](/blog/phpunit-ile-ilk-testlerimi-yazmak) zor değildi; ama her test dosyası bir sınıf, her test bir metot, `$this->assertSomething()` zincirleri... Sözdizimi küçük bir sürtüşme yaratıyordu ve bu sürtüşme birikince test yazmak ertelenir hale geldi.

Pest'i gördüğümde ilk tepkim "başka bir araç mı" oldu. Bir süre bekledim. Bu yılın başında ciddi bir projeye Pest ile test yazmaya başladım ve artık PHPUnit'e dönmek istemiyorum. Bu yazıda neden olduğunu anlatmaya çalışacağım.

## Pest nedir

Pest (Pest PHP), Laravel ekibinin yakın çevresinden Nuno Maduro tarafından geliştirilen, PHPUnit üzerine inşa edilmiş bir test çerçevesidir (testing framework). PHPUnit'i değiştirmiyor; onun üstüne daha temiz bir sözdizimi koyuyor. Bu önemli: mevcut PHPUnit testlerinizi Pest ile çalıştırabilirsiniz, geçiş aşamalı olabiliyor.

## Sözdizimi farkı

PHPUnit ile bir Feature testi:

```php
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AuthTest extends TestCase
{
    use RefreshDatabase;

    public function test_user_can_login_with_valid_credentials(): void
    {
        $user = User::factory()->create([
            'password' => bcrypt('gizli123'),
        ]);

        $response = $this->post('/api/login', [
            'email'    => $user->email,
            'password' => 'gizli123',
        ]);

        $response->assertStatus(200)
                 ->assertJsonStructure(['token']);
    }

    public function test_user_cannot_login_with_wrong_password(): void
    {
        $user = User::factory()->create();

        $response = $this->post('/api/login', [
            'email'    => $user->email,
            'password' => 'yanlis',
        ]);

        $response->assertStatus(401);
    }
}
```

Aynı testler Pest ile:

```php
<?php

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

it('kullanıcı geçerli bilgilerle giriş yapabilir', function () {
    $user = User::factory()->create([
        'password' => bcrypt('gizli123'),
    ]);

    $this->post('/api/login', [
        'email'    => $user->email,
        'password' => 'gizli123',
    ])
    ->assertStatus(200)
    ->assertJsonStructure(['token']);
});

it('kullanıcı yanlış şifreyle giriş yapamaz', function () {
    $user = User::factory()->create();

    $this->post('/api/login', [
        'email'    => $user->email,
        'password' => 'yanlis',
    ])
    ->assertStatus(401);
});
```

Sınıf yok, `namespace` yok, metot yok. `it()` veya `test()` fonksiyonu, string olarak test açıklaması, bir closure. Bu kadar.

## Expectations (beklentiler) sözdizimi

Pest kendi `expect()` API'sini de sunuyor; `assertXxx` metotları yerine zincirleme kullanılabiliyor:

```php
<?php

it('sipariş toplam fiyatı doğru hesaplanır', function () {
    $order = Order::factory()
        ->hasItems(3, ['price' => 100])
        ->create();

    expect($order->total)
        ->toBe(300)
        ->toBeGreaterThan(0);
});
```

`expect()->toBe()` okumak için çok daha doğal geliyor. Test çıktısı da aynı şekilde daha okunabilir.

## Dataset ile parametre geçmek

Aynı testi farklı girdilerle çalıştırmak için PHPUnit'te `dataProvider` yazıyordunuz. Pest'te daha az tören:

```php
<?php

it('geçersiz e-posta formatlarını reddeder', function (string $email) {
    $this->post('/api/register', ['email' => $email])
         ->assertStatus(422);
})->with([
    'düz metin',
    '@eksik-lokal.com',
    'eksik-@alan.com',
    'boşluk içeren@alan.com',
]);
```

PHPUnit'te `dataProvider` şöyle yazılıyordu: ayrı bir `public function` tanımlayacaksınız, `@dataProvider` docblock'u ekleyeceksiniz, metot adını eşleştireceksiniz. Pest'te `.with()` — hepsi bu. Sınır durumları (edge case) test etmeye teşvik eden bir ergonomi; parametreli testi yazmak kolaylaşınca daha fazla senaryo test ediyorsunuz.

## Kurulum ve geçiş

```bash
composer require pestphp/pest --dev --with-all-dependencies
composer require pestphp/pest-plugin-laravel --dev
php artisan pest:install
```

Mevcut PHPUnit testleri dokunulmadan çalışmaya devam eder. Yeni testleri Pest ile yazmak yeterli; aşamalı geçiş mümkün.

Birlikte çalışma konusunda dikkat ettiğim bir şey: Pest'in `tests/Pest.php` dosyasında `uses()` ile belirlenen helper'lar tüm dosyalar için geçerli olabiliyor. Bu bazen beklenmedik durumlar çıkarabiliyor; örneğin bir test grubuna `RefreshDatabase` eklemek istiyorsanız ilgili dosyada `uses(RefreshDatabase::class)` yazmak, global tanımlamaya güvenmekten daha güvenli.

## Yalnızca belirli bir testi çalıştırmak

Büyük bir test paketinde yalnızca üzerinde çalıştığınız testi çalıştırmak istiyorsunuz. Pest'te bunu `--filter` seçeneğiyle yapıyorsunuz:

```bash
php artisan test --filter "kullanıcı geçerli bilgilerle giriş yapabilir"
```

Ya da test dosyasını belirterek:

```bash
php artisan test tests/Feature/AuthTest.php
```

PHPUnit'te de bunlar mümkün ama Pest'in test açıklamaları string olduğu için `--filter` ile aramak daha doğal. `test_user_can_login_with_valid_credentials` yerine `kullanıcı geçerli bilgilerle giriş yapabilir` gibi Türkçe açıklamalar yazabiliyorsunuz; filtre de aynı şekilde çalışıyor.

## Asıl kazanım: sürtüşme azaldı

Pest'i benimsedikten sonra fark ettiğim şey hız değildi (çalışma süresi PHPUnit ile neredeyse aynı). Asıl fark, yeni bir özellik yazdıktan sonra test açmak için duyulan direnç azaldı. Sözdizimi kısaldıkça "şunu da test edeyim" kararını vermek kolaylaştı.

Bu, araç seçiminin davranışı nasıl etkilediğine iyi bir örnek. Teknik bir fark olmasa da ergonomi üzerindeki etkisi gerçek. Test yazmayı güzel bulmak zorunda değilsiniz; ama mümkün olduğu kadar az sürtüşme yaratmasını isteyebilirsiniz.

Pest'e geçiş, test yazmayı daha sık yapmamı sağladı — ama asıl değişim alışkanlıkta oldu. Bir özelliği bitirmeden önce en az temel senaryoları yazmak bir reflekse dönüştü. Araç bunu dayatmıyor; ama kapıyı açık tutuyor. Sürtüşme azaldıkça "sonra yazarım" ertelemesi de azalıyor.
