Her ekip otomatik teste değer verdiğini söyler; ama yeşil bir pipeline'la, bir insanın çift kontrolüne gerek kalmadan üretime çıkabilen ekip çok daha azdır. Fark, hangi test türlerinin adını sayabildiğiniz değildir — test setinin nasıl şekillendirildiği, neye karşı çalıştığı ve pipeline'ın "hayır" deme yetkisinin olup olmadığıdır. İşte pratikte uyguladığımız strateji.

Test Piramidi Hâlâ Geçerli

Klasik biçim doğru varsayılan olmayı sürdürüyor: tabanda çok sayıda hızlı unit test, daha küçük bir entegrasyon testi katmanı ve tepede ince bir uçtan uca (end-to-end) test dilimi. Gerekçe ekonomik. Vitest, JUnit 5 ya da pytest ile yazılmış bir unit test milisaniyeler içinde çalışır ve hatalı fonksiyonu nokta atışı gösterir; bir uçtan uca test dakikalar alır, birbiriyle ilgisiz bir düzine nedenden ötürü çakılabilir ve size yalnızca bir şeylerin bozulduğunu söyler. Piramidi ters çeviren ekipler — yüzlerce tarayıcı testi, az sayıda unit test — bir saat süren ve artık kimsenin dikkate almadığı pipeline'larla baş başa kalır. Regresyon koruması bundan bedavaya çıkar: her değişiklikte çalışan mevcut test setiniz, eski davranışın hâlâ geçerli olduğunu doğrulayan şeydir. Uyumluluğu garanti edemez; yalnızca kırılmayı kullanıcılarınızdan önce yakalayabilir — ki mesele de zaten budur.

Gerçek Bağımlılıklara Karşı Entegrasyon Testleri

En yaygın test yalanı, mock'lanmış bir veritabanıdır. Mock'lar, kodunuzun driver'ı sizin varsaydığınız şekilde çağırdığını doğrular — sorgunun çalıştığını değil. Testcontainers bu ekonomiyi değiştirdi: test setiniz Docker'da gerçek bir PostgreSQL, Redis ya da Kafka ayağa kaldırır, ona karşı çalışır ve işi bitince kapatır — hem lokalde hem CI'da. Mock'ları, üçüncü taraf API'ler gibi gerçekten kontrol edemediğiniz sınırlara saklayın — ve o sınırları da bunun yerine contract testlerle kapsayın.

Servis Sınırları için Contract Testing

Bir mikroservis ortamında contract testing'in alternatifi, her servisin uçtan uca test setinin diğer tüm servislere karşı koştuğu paylaşılan bir staging ortamıdır — yavaş, flaky ve maliyeti karesel büyüyen bir düzen. Pact ile consumer-driven contract testing bunu tersine çevirir: her consumer, bağımlı olduğu istek ve yanıtları tam olarak yayımlar; her provider bu sözleşmeleri kendi pipeline'ında doğrular. Bir consumer'ı kıran provider bunu build anında, izole biçimde ve işin içine staging ortamı karışmadan öğrenir.

Uçtan Uca — Ama İdareli

Playwright (ya da Cypress) ile uçtan uca testler, maliyetlerini yalnızca bir hatanın olay (incident) anlamına geldiği yolculuklarda çıkarır: kayıt, giriş, ödeme, ürününüzün çekirdek iş akışı. Sayıyı yüzlerde değil onlarda tutun, testleri üretim benzeri bir ortama karşı çalıştırın ve bir unit testin aynı hatayı üç katman daha ucuza yakalayacağı yerde tarayıcı testine uzanma dürtüsüne direnin.

Shift Left: CI'da Kalite Kapıları

Shift-left, kontrollerin pull request üzerinde, merge'den önce çalışması demektir — gece koşusunda değil, bir hardening sprint'inde değil. Somut olarak bu; lint'in, coverage eşikli unit testlerin ve entegrasyon testlerinin tamamının zorunlu status check olduğu ve hepsi geçene kadar merge'ün bloklandığı bir CI pipeline'ı demektir. Minimal bir GitHub Actions örneği:

name: ci
on:
  pull_request:

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v5
      - uses: actions/setup-node@v5
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm run lint
      - run: npm test -- --coverage
      - run: npm run test:integration

Kapı, araç setinden daha önemlidir: kırmızı bir pipeline yine de merge edilebiliyorsa, elinizde kalite kapısı yok demektir — sadece öneriler vardır. Coverage eşiklerini oynanacak bir hedef olarak değil, erozyona karşı bir taban olarak görün; anlamlı assertion'larla %80, hiçbir şey doğrulamayan testlerin %95'inden iyidir.

Flaky Testleri Yönetmek

Flaky testler bir rahatsızlık değil, korozyondur. Mühendisler yeniden çalıştırmanın hataları "düzelttiğini" öğrendiği anda, gerçek hataları da yeniden çalıştırmaya başlar. İşleyen politika şudur: CI'da tekrar-sonrası-geçme (pass-after-retry) oranlarını izleyerek flake'leri tespit edin, ana pipeline güvenilir kalsın diye onları derhal bloklamayan bir job'a karantinaya alın ve karantinadaki her teste bir sahip ve bir son tarih verin — ya düzeltilir ya silinir. Otomatik retry'lar yalnızca bir tespit mekanizması olarak kabul edilebilir, asla kalıcı bir geçici çözüm olarak değil.

Sonuç

İşleyen bir strateji gösterişsizdir: piramit biçiminde bir test seti, gerçek bağımlılıklara karşı entegrasyon testleri, servis sınırlarında sözleşmeler, bir avuç uçtan uca yolculuk, CI'da sert kapılar ve flake'lere sıfır tolerans. Bunları doğru yapın; deployment bir olay olmaktan çıkar. Pipeline'ınız henüz o noktada değilse, DevOps ekibimiz tam olarak bu tür teslimat makineleri kuruyor.

Bunu üretimde mi çalıştıracaksınız? AWS Yönetilen Hizmetler ekibimiz bu tür ortamları 7/24 işletiyor — izleme, olay müdahalesi, yama yönetimi ve maliyet kontrolü, isimleri belli kıdemli mühendislerle, aylık 3.000 €'dan başlayan fiyatlarla.