---
title: "Test Verisini Fixture Yerine Kurucu (Builder) ile Üretmek"
url: "https://cilginyazilim.com/blog/test-verisi-builder-deseni"
description: "Paylaşılan fixture dosyaları testleri neden kırılganlaştırır? Test verisi kurucu (builder) deseni, varsayılan değerler ve okunabilir testler."
published: "2026-09-24T10:00:00+03:00"
modified: "2026-09-24T10:00:03+03:00"
author: "Çılgın Yazılım"
category: "Yazılım Geliştirme"
tags: ["php", "kalite güvencesi", "birim testi", "test otomasyonu", "phpunit", "yazılım testi", "kırılgan test", "test kalitesi", "test verisi", "okunabilirlik", "builder deseni", "fixture", "factory"]
site: "Çılgın Yazılım"
language: "tr"
---

# Test Verisini Fixture Yerine Kurucu (Builder) ile Üretmek

Paylaşılan fixture dosyaları zamanla kimsenin dokunmaya cesaret edemediği bir bağımlılık yumağına dönüşür. Kurucu deseni bunu çözer.

**Test verisi** üretmek, test yazmanın en çok küçümsenen kısmıdır. Çoğu proje paylaşılan bir fixture dosyasıyla başlar: içinde on beş kullanıcı, yirmi sipariş ve birkaç kategori bulunan büyük bir dizi. İlk aylarda pratiktir. Bir yıl sonra ise kimse ona dokunmaya cesaret edemez, çünkü tek bir alanı değiştirmek onlarca testi kırar.

![Fixture ve kurucu deseninin karşılaştırması](https://cilginyazilim.com/uploads/blog/2026/08/test-verisi-builder-deseni-ozet.png)
*İyi bir test, ilgilendiği alan dışındaki hiçbir veriyi göstermez.*

## Paylaşılan fixture neden bozulur?

Üç sebep birikir. Birincisi **görünmez bağımlılık**: test "3 numaralı kullanıcı" der, ama o kullanıcının neden özel olduğu testte yazmaz — bilgi fixture dosyasındadır. İkincisi **gizli kaplin**: fixture'a yeni bir alan eklemek, o alanı hiç umursamayan testleri de etkiler. Üçüncüsü **okunmazlık**: testi okuyan kişi, senaryonun hangi koşula dayandığını anlamak için başka bir dosyaya gitmek zorunda kalır.

> Bir testi anlamak için başka bir dosyayı açmanız gerekiyorsa, o test dokümantasyon değeri taşımıyor demektir. Testlerin en büyük ikinci faydası tam olarak budur.

## Kurucu deseni: makul varsayılan + açık fark

Kurucu (builder), geçerli bir nesneyi varsayılan değerlerle kuran ve yalnızca testin ilgilendiği alanların değiştirilmesine izin veren küçük bir sınıftır.

```php
final class KullaniciKurucu
{
    private array $veri;

    public function __construct()
    {
        // Her alan GEÇERLİ bir varsayılan alır; test yalnızca farkı belirtir
        $this->veri = [
            'ad'       => 'Test Kullanıcı',
            'eposta'   => 'test' . bin2hex(random_bytes(4)) . '@example.com',
            'rol'      => 'user',
            'aktif'    => 1,
            'bakiye'   => 10000,
            'olusturuldu' => '2026-01-01 09:00:00',
        ];
    }

    public static function bir(): self
    {
        return new self();
    }

    public function rolIle(string $rol): self
    {
        $kopya = clone $this;
        $kopya->veri['rol'] = $rol;

        return $kopya;      // değiştirilemez zincir: yan etki üretmez
    }

    public function pasif(): self
    {
        $kopya = clone $this;
        $kopya->veri['aktif'] = 0;

        return $kopya;
    }

    public function bakiyesiz(): self
    {
        $kopya = clone $this;
        $kopya->veri['bakiye'] = 0;

        return $kopya;
    }

    public function dizi(): array
    {
        return $this->veri;
    }

    public function kaydet(): int
    {
        return (int) (new UserModel())->insert($this->veri);
    }
}
```

## Testler birden okunur hâle gelir

```php
public function testPasifKullaniciGirisYapamaz(): void
{
    // Senaryonun TEK ilgili koşulu burada, göz önünde
    $id = KullaniciKurucu::bir()->pasif()->kaydet();

    $sonuc = $this->authService->girisDene($id, 'parola');

    $this->assertFalse($sonuc->basarili);
    $this->assertSame('hesap_pasif', $sonuc->kod);
}

public function testBakiyesizKullaniciSiparisVeremez(): void
{
    $id = KullaniciKurucu::bir()->bakiyesiz()->kaydet();

    $this->expectException(YetersizBakiye::class);
    $this->siparisServisi->olustur($id, ['urun' => 'kalem']);
}
```

İki test de tek bakışta anlaşılıyor: birinde kullanıcı pasif, diğerinde bakiyesi yok. Geri kalan tüm alanlar geçerli ama *görünmez*, çünkü senaryoyla ilgileri yok. Bu, kırılgan testlerin en yaygın sebeplerinden birini — paylaşılan duruma bağlılığı — kökünden kaldırır; konuyu [kırılgan testler güveni nasıl öldürür](https://cilginyazilim.com/blog/kirilgan-flaky-testler-guveni-nasil-oldurur) yazımızda genişçe ele almıştık.

Kurucuları ve test komutlarını tek bir yerde toplamak için [Makefile](https://cilginyazilim.com/blog/makefile-ile-proje-komutlarini-standartlastirmak) pratik bir üst katmandır.

## Benzersizlik ve yalıtım

Kurucudaki e-posta alanına rastgele bir ek konulduğuna dikkat edin. Sabit bir e-posta kullanmak, benzersizlik kısıtı olan tablolarda testleri birbirine bağlar ve paralel çalıştırmayı imkânsız kılar. Aynı mantık [kapsam yüksek ama hatalar devam ediyor](https://cilginyazilim.com/blog/test-kapsami-yuksek-ama-hatalar-devam-ediyor) tartışmasıyla da örtüşür: sorun test sayısında değil, testlerin neyi gerçekten doğruladığındadır.

Aynı ilke yapılandırma için de geçerlidir: testte açık/kapalı davranışı sınamanız gerekiyorsa [özellik bayraklarını](https://cilginyazilim.com/blog/ozellik-bayraklari-feature-flag) kurucudan verilebilir hâle getirin.

## Ne zaman fixture hâlâ doğru seçim?

Referans veriler için — ülke listesi, para birimleri, izin türleri gibi nadiren değişen ve tüm sistemin dayandığı tablolar için — fixture uygundur. Ayrım şudur: **senaryoya özel veri** kurucu ile, **sistem sabitleri** fixture ile üretilmelidir. PHPUnit tarafındaki kurulum/temizlik kancaları için [PHPUnit fixture belgeleri](https://docs.phpunit.de/en/10.5/fixtures.html) güncel referanstır.

## Sonuç

Test verisi üretme biçimi, test paketinin uzun vadeli sağlığını doğrudan belirler. Paylaşılan fixture'lar zamanla görünmez bağımlılıklar biriktirir ve küçük bir şema değişikliği onlarca testi kırar. Kurucu deseni bunu tersine çevirir: her test kendi verisini kurar, yalnızca ilgilendiği farkı belirtir ve okuyan kişi senaryoyu tek dosyada görür. Bir sonraki testinizi yazarken şu soruyu sorun — "bu test hangi koşulu doğruluyor?" Cevap testin ilk satırında görünmüyorsa, bir kurucuya ihtiyacınız var demektir.

## Pratik Uygulama Kontrol Listesi

Bu yazıdaki önerileri kendi ekibinize uyarlarken aşağıdaki adımları sırasıyla uygulamanız, teoriden pratiğe geçişi kolaylaştırır:

1. **Mevcut durumu ölçün.** Değişiklik yapmadan önce bugünkü performansı/süreyi/hata oranını kaydedin; aksi halde iyileşmeyi kanıtlayamazsınız.
2. **Küçük bir pilot seçin.** Tüm sisteme veya tüm ekibe birden uygulamak yerine tek bir modülde veya tek bir sprintte deneyin.
3. **Sonuçları ekiple paylaşın.** Elde ettiğiniz veriyi (olumlu ya da olumsuz) kısa bir notla ekibe aktarın; kararın gerekçesi belgelenmemişse aynı tartışma birkaç ay sonra tekrar açılır.
4. **Süreci tekrarlanabilir hale getirin.** İşe yarayan pratiği bir kontrol listesine veya şablona dönüştürün ki yeni katılan ekip üyeleri de aynı standardı hızlıca öğrensin.

> Test Verisi konusunda attığınız her küçük adım ölçülebilir olduğu sürece değerlidir; büyük ve tek seferlik dönüşümler yerine sürekli, küçük iyileştirmeler uzun vadede daha kalıcı sonuç verir.

## Sık Yapılan Yanlışlar

Bu konuda ekiplerin en çok düştüğü tuzak, çözümü tek bir kişiye ya da tek bir araca yüklemektir. Oysa kalıcı iyileşme, sürecin ekibin günlük rutinine (code review kontrol listesi, sprint planlama, onboarding dokümanı gibi) gömülmesiyle mümkün olur. İkinci yaygın hata ise "en iyi pratiği" olduğu gibi kopyalamaktır — başka bir ekipte işe yarayan bir yaklaşım, farklı bir ölçekte veya farklı bir teknoloji yığınında aynı sonucu vermeyebilir; önce kendi bağlamınızda küçük ölçekte test edin, sonra genişletin. Üçüncü tuzak ise ölçmeden karar vermektir: "daha iyi hissettiriyor" öznel bir gerekçedir, ekip içi tartışmalarda nesnel veriyle desteklenmeyen kararlar er ya da geç sorgulanır ve geri alınır. Son olarak, dokümantasyonu atlamak da sık görülen bir hatadır: bir kararın "neden" alındığı yazılı değilse, ekip altı ay sonra aynı tartışmayı sıfırdan yeniden yapmak zorunda kalır ve önceki deneyimden öğrenilenler kaybolur.

## Sonuç

Test Verisini Fixture Yerine Kurucu (Builder) ile Üretmek konusunda burada değindiğimiz noktalar, konuyu ilk kez ele alan ekipler için de deneyimli geliştiriciler için de pratik bir kontrol listesi görevi görür. test verisi üzerine çalışırken en çok fayda sağlayan yaklaşım, tek seferde her şeyi mükemmelleştirmeye çalışmak yerine küçük, ölçülebilir adımlarla ilerlemektir. Ekibinizde bu konuyu bir sonraki sprint retrospektifinde veya teknik tartışma toplantısında gündeme getirmenizi, burada anlatılan pratiklerden hangilerinin sizin bağlamınıza uyduğunu birlikte değerlendirmenizi öneririz. Sonuç olarak, doğru araçları seçmek kadar bunları ekip kültürüne oturtmak da başarıyı belirleyen asıl etkendir.

## Sıkça Sorulan Sorular

### Kurucu yazmak fazladan iş değil mi?

İlk kurucu için evet, yaklaşık yarım saat. Ancak o kurucu onlarca testte kullanılır ve her yeni test için veri hazırlama süresini neredeyse sıfıra indirir. Asıl kazanç ise şema değiştiğinde tek bir dosyayı güncellemenizin yetmesidir.

### Kurucu ile factory arasındaki fark nedir?

Pratikte sınır bulanıktır. Factory genelde "geçerli bir nesne üret" görevini üstlenir; kurucu ise buna okunabilir bir zincirleme arayüz ekler. Birçok projede ikisi tek sınıfta birleşir ve bu sorun değildir.

### Kurucular veritabanına yazmak zorunda mı?

Hayır ve zorunlu olmamalıdır. İyi bir kurucu hem sadece dizi/nesne döndürebilmeli hem de istendiğinde kaydedebilmelidir. Böylece aynı kurucu, veritabanına hiç dokunmayan hızlı birim testlerinde de kullanılabilir.

### Çok sayıda ilişkili kayıt gerektiren senaryolarda ne yapmalı?

Kurucuları iç içe kullanın: sipariş kurucusu, içeride kullanıcı kurucusunu çağırabilir. Testte yalnızca ilgilendiğiniz seviyeyi belirtir, gerisini varsayılanlara bırakırsınız. Bu, karmaşık senaryolarda bile testin okunur kalmasını sağlar.

---

Kaynak: [Test Verisini Fixture Yerine Kurucu (Builder) ile Üretmek](https://cilginyazilim.com/blog/test-verisi-builder-deseni)
