İçeriğe geç
Muhammet Şafak
Araçlar & Teknolojiler 3 dk okuma

PHPUnit ile ilk testlerimi yazmak

PHPUnit kurulumundan başlayarak ilk birim testlerimi nasıl yazdığımı, hangi şeylerin işe yaradığını ve hangi tuzaklara düştüğümü anlatıyorum.


Test yazmayı uzun süre erteledim. “Projeyi bitireyim, sonra test eklerim” cümlesi yıllarca aklımın bir köşesinde durdu ve o “sonra” hiç gelmedi. Bu yıl farklı yaptım; küçük bir özellik üzerinde PHPUnit ile gerçekten test yazmaya oturdum. Bu yazı o deneyimi aktarıyor; teorik değil, pratikte neler yaptığım.

PHPUnit kurulumu

Laravel kullanıyorsanız PHPUnit zaten composer.json dosyasının require-dev bölümünde hazır geliyor. Harici bir projede eklemek için:

composer require --dev phpunit/phpunit

Proje kökünde bir phpunit.xml yapılandırma dosyası oluşturmak iyi bir alışkanlık. Laravel bu dosyayı varsayılan olarak sağlıyor; başka projelerde en sade hâliyle şöyle görünüyor:

<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php" colors="true">
    <testsuites>
        <testsuite name="Application Test Suite">
            <directory>tests</directory>
        </testsuite>
    </testsuites>
</phpunit>

İlk birim testi

Unit test, tek bir sınıfı ya da metodu yalıtılmış şekilde test etmek demek. Dış bağımlılıkları, veritabanını, harici servisleri devre dışı bırakıp yalnızca o metodun doğru çalışıp çalışmadığını soruyorsunuz.

Bir fiyat hesaplama sınıfı üzerinden başladım. Sınıf basit: miktarı alıyor, vergiyi ekliyor, toplam fiyatı döndürüyor.

<?php

namespace App\Services;

class PriceCalculator
{
    public function withTax(float $price, float $taxRate = 0.18): float
    {
        return round($price * (1 + $taxRate), 2);
    }
}

Bu sınıf için test:

<?php

namespace Tests\Unit;

use App\Services\PriceCalculator;
use PHPUnit\Framework\TestCase;

class PriceCalculatorTest extends TestCase
{
    public function test_withTax_returns_correct_total()
    {
        $calculator = new PriceCalculator();

        $result = $calculator->withTax(100.00);

        $this->assertEquals(118.00, $result);
    }

    public function test_withTax_applies_custom_rate()
    {
        $calculator = new PriceCalculator();

        $result = $calculator->withTax(200.00, 0.08);

        $this->assertEquals(216.00, $result);
    }
}

Testi çalıştırmak için:

./vendor/bin/phpunit tests/Unit/PriceCalculatorTest.php

Yeşil çıktı gördüğümde küçük ama somut bir tatmin hissettim. “Bu kod doğru çalışıyor” diye bilmek değil; “bu kodun doğru çalıştığını kanıtlayan bir şey var” diye bilmek.

Test yazarken fark ettiğim şeyler

İlk birkaç testten sonra şunu anladım: test yazmak zor değil ama testable kod yazmak dikkat istiyor.

Başlangıçta bir metodun içine veritabanı sorgusu, dosya okuma ve iş mantığını aynı anda koyuyordum. Bunu test etmek istedim mi? Veritabanı olmadan mümkün değildi. Bu durum bir bölme işaretiydi: eğer bir metodu yalıtılmış test edemiyorsam, o metod muhtemelen çok fazla sorumluluk üstlenmiş demektir.

Testi yazmak, kodu kademeli olarak daha temiz hâle getirmeye zorladı.

Laravel özellik testleri

Laravel, unit testlerin yanı sıra feature test yazmayı da kolaylaştırıyor. Bu testler bir HTTP isteği simüle ediyor; gerçek bir tarayıcı olmadan rotaların, controller’ların ve middleware’in birlikte çalıştığını doğrulayabiliyor.

<?php

namespace Tests\Feature;

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

class OrderTest extends TestCase
{
    use RefreshDatabase;

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

        $response = $this->actingAs($user)
            ->postJson('/api/orders', [
                'product_id' => 1,
                'quantity'   => 2,
            ]);

        $response->assertStatus(201);
        $this->assertDatabaseHas('orders', ['user_id' => $user->id]);
    }
}

RefreshDatabase trait’i her testten önce veritabanını sıfırlıyor, testler birbirini etkilemiyor. actingAs ile kullanıcıyı oturum açmış gibi simüle edebiliyorum. Bu altyapı sayesinde test yazmak koşullar altında da pratik kalıyor.

Neyi test edeceğinizi seçmek

Her şeyi test etmek gerekmiyor ve mümkün de değil. Başlangıçta neyin önemli olduğunu belirlemek önemli. Benim şu an odaklandığım yerler:

  • İş mantığı barındıran servis sınıfları
  • Hesaplama, dönüşüm, filtreleme gibi saf fonksiyonlar
  • API uç noktaları — özellikle veri kabul etmesi ya da reddetmesi gereken yerler

Getter/setter gibi trivial metodları, basit çıktıları test etmek zamanı boşa harcamak. Hata yapıldığında maliyeti yüksek olan mantığa öncelik veriyorum.

Sonuç

İlk testleri yazmak ciddi bir öğrenme eğrisi değil. Zor olan kısmı alışkanlığa dönüştürmek. Ben küçük başladım: var olan bir servis sınıfına test ekledim, orada durdum, sonra bir tane daha. Test yazma ritmi tutturulduğunda, “bunu test edebilir miyim” sorusunu kod yazarken de sormaya başladım. Bu sorgulamak, sonuç olarak kodu daha iyi yönde şekillendiriyor.

Etiketler: #PHP#Test
Paylaş:

İlgili Yazılar

Sitede Ara

Yazı, proje ve sayfalarda arama yapmak için yazmaya başlayın.

Esc ile kapat Pagefind ile güçlendirildi