Referans Rehberi · Test

Testler ne zaman gerçekten karşılığını verir?

Testler hakkındaki metinlerin çoğu framework'lerden söz eder. Bu metin ise ekonomiden söz ediyor: Testler ne zaman değer yaratır, ne zaman getirdiklerinden fazlasına mal olur? CTO'lar, mühendislik yöneticileri, tech lead'ler ve kıdemli geliştiriciler için.

Bu nedir? · Referans Rehberi

Bir mühendislik problemini inceleyen derinlemesine bir rehber — riskler, maliyetler ve farklı karar verdiğimiz senaryolar dahil. Bir makale değil, bir başvuru metni. Genel bakışa git

Yazar
Batunet Engineering
Okuma süresi
13 dk
Seviye
İleri düzey
Durum
Onaylandı
Son inceleme
21 Temmuz 2026
Güncelleme
21 Temmuz 2026
Bu sayfada

Geliştirme ekiplerinde testler kadar inatla tartışılan konu azdır ve tartışma neredeyse her zaman bir karakter meselesi olarak yürütülür: bir taraf disiplinli, diğer taraf özensiz. Tartışmanın hiç bitmemesinin nedeni budur — ahlaki bir sorunun yanıtı yoktur, yalnızca kampları vardır.

Bu metin testleri ne bir erdem ne de bir yük olarak ele alır; oldukları şey olarak ele alır: bir yatırım. Her testin bir maliyeti vardır — onu yazmanın, bakımını yapmanın, çalıştırmanın ve sabitlediği tasarımın. Ve her test bir şey getirir — güvenli hâle gelen bir değişiklik, üretime çıkmayan bir hata. Bu yatırımın getirisi, neyi test ettiğinize bağlı olarak muazzam ölçüde dalgalanır. Bazı testler kendini kat kat öder. Diğerleri kalıcı olarak maliyet üretir ve hiçbir şey yakalamaz. Bu yüzden tek faydalı soru “yeterince test ediyor muyuz?” değil, “bu test değer mi?” sorusudur.


Ekipler testler hakkında neden tartışır

Tartışmanın iki kampı vardır ve ikisi de diğeri hakkında haklıdır. Bir kamp kapsamı (coverage) erdeme dönüştürür: Test edilmemiş olan bitmemiş sayılır, hedef yüksek bir yüzdedir. Bu kamp zamanla, gerçek tek bir hata yakalamadan her yeniden yapılandırmada kırılan kırılgan test kodunda boğulur — ve değişiklik pahalı hâle gelir. Diğer kamp tam olarak bunu yaşar ve testlerin yalnızca yavaşlattığı sonucuna varır; daha hızlı teslim eder ve bedelini sonradan, kimsenin öngörmediği hatalarla öder.

İkisi de diğerinin belirtisini doğru teşhis etmiş, kendi nedenini ise gözden kaçırmıştır. Hata her iki tarafta da aynıdır: “Test etmeyi” bir seçim meselesi olarak değil, bir miktar — daha çok ya da daha az — olarak ele alırlar. Kapsam, ne kadar riskin güvence altına alındığını değil, ne kadar kodun çalıştırıldığını ölçer. Bir girdi büyüklüğüdür, bir değer değil. Soruyu ekonomik olarak sorduğunuz anda — bu test neye mal oluyor ve neyi satın alıyor — inanç savaşı çözülür. Doğru bir test miktarı yoktur. Yalnızca değen testler ve değmeyen testler vardır.

Bu ekonomiyi acımasız kılan ve neredeyse her zaman gözden kaçan bir nokta vardır: Bir test kendisi de koddur. Yazdığınız, okuduğunuz ve bakımını yaptığınız, üretim kodundaki her değişiklikte birlikte elden geçirilmesi gereken ve kendisi de hata içerebilen ikinci bir sistemdir. Dolayısıyla kötü bir test nötr değil, hiç olmamasından daha kötüdür — kalıcı olarak bakım maliyeti üretir, sahte bir güvenlik hissi yaratır ve teşvik etmek istediğiniz yeniden yapılandırmayı, gerçek tek bir hata yakalamadan cezalandırır. Testleri bedava sanan, hesabın yalnızca yarısını görür ve sonradan test paketinin ekibi taşımak yerine neden yavaşlattığına şaşırır.

Gerçekte neyin test edilmesi gerekir

Bir testin değeri adlandırılabilir. Bu noktada bir hatanın ortaya çıkma olasılığı ne kadar yüksekse, bu hata üretimde ne kadar pahalıya mal olacaksa ve test gelecekteki değişiklikleri ne kadar çok güvence altına alıyorsa, değeri o kadar yüksektir. Maliyeti ise yazılması ve — özellikle — bakımı ne kadar zahmetliyse, test edilen kod ne sıklıkla değişiyorsa ve test davranışa değil de uygulama ayrıntılarına ne kadar yapışıksa o kadar yüksektir. Bir test, değerin maliyeti açıkça aştığı yerde değer.

Neyin test edileceği buradan çıkar: bir hatanın pahalı olduğu ve davranışın testin onu aşacağı kadar istikrarlı olduğu noktalar. Bunlar iş kurallarıyla birlikte alanın çekirdeği, bir hatanın gerçek zarar verdiği yollar — para, veri bütünlüğü, güvenlik, geri alınamaz olan —, istikrarlı kamuya açık sözleşmeler ve çok sayıda sınır durumu içeren çetrefilli hesaplamalardır. Mihenk taşı “bu satır kapsanıyor mu?” değil, “burada bir hata pahalı olur muydu ve bu test gelecek ay da geçerli olacak mı?” sorusudur.

Bir testin değeri hata yakalamakla da sınırlı değildir. İyi bir test aynı zamanda çalıştırılabilir bir spesifikasyondur: Kodun ne yapması gerektiğini, birlikte çalıştığı için eskiyemeyecek bir biçimde kayda geçirir. Bir kuralı değiştiren, kırılan testten hangi taahhütlere dokunduğunu hemen görür — test, kodun kendisinde çoğu zaman yalnızca örtük olarak duran niyeti görünür kılar. Bu ikinci fayda birinciyi güçlendirir: Tam da pahalı, mantık yoğun noktalarda belgelenmiş niyet, yakalanan hata kadar değerlidir ve ikisi de aynı yatırıma katkı sağlar.

Önerimiz: Testleri kapsama göre değil, hata maliyetine ve istikrara göre seçin. Bedeli, önemli olan güvence altında olsa bile kapsam oranının düşük görünebilmesidir — bunu metrik beklentilerine karşı savunmanız gerekir. Hatası ucuz olacak ve hemen görünür hâle gelecek kodda farklı karar veririz; orada düşük bir test derinliği bile savunulabilir, çünkü sonuçsuz bir bug hızla fark edilir ve ucuza düzeltilir.

Testler en yüksek ROI'yi nerede sağlar

Bir test için en iyi yer, üç şeyin bir araya geldiği yerdir: yüksek hata maliyeti, düşük değişim oranı ve dar bir alanda yoğun mantık. Tam orada test yazması ucuzdur, pahalı hataları yakalar ve bakım gerektirmeden uzun süre yaşar.

test edin — en iyi ROI davranışı test edin, ayrıntıları değil az gerekli test etmeyin — negatif ROI yüksek düşük düşük yüksek Değişkenlik / değişim oranı → Bir hatanın maliyeti →

Şema: Testin değeri hata maliyetiyle artar, değişim oranıyla düşer.

Somut olarak bunlar: dallanmalar içeren saf hesaplamalar — fiyat, vergi ya da indirim mantığı —; test etmesi ucuzdur ve pahalı hataları yakalar; her zaman geçerli olması gereken alan değişmezleri (invariant'lar); bir kırılmanın başka sistemleri etkilediği dışa dönük sözleşme sınırları; ve bir regresyon testi olarak sabitlenen, yeniden üretilmiş her bug — çünkü bir kez olmuş bir hata yeniden olur.

Önerimiz: Önce mantık yoğun, pahalı, istikrarlı kod için testlere yatırım yapın — ve her gerçek bug'ı bir regresyon testi olarak sabitleyin. Bedeli, rahatsız edici bir noktada disiplindir: Pahalı çekirdek çoğu zaman aynı zamanda en az dokunmak istediğiniz yerdir. Henüz denenme aşamasında olan ve sık değişen bir hesaplamada farklı karar veririz; orada testi her iterasyonda yeniden yazmak yerine hesaplama istikrar kazanana kadar bekleriz.

Testler nerede faydadan çok bakım yükü üretir

Negatif getirili bölgeler vardır — kalıcı olarak maliyet üreten ve nadiren bir şey yakalayan testler. Bunlar hiç test etmemekten daha tehlikelidir, çünkü güveni ve hızı aynı anda baltalar.

İlk alan, mantık içermeyen önemsiz koddur: bağlantı kodu, değerleri aktarma, basit erişim metotları. Bunun için yazılan bir test aslında dilin çalıştığını doğrular. İkincisi, testten daha hızlı değişen değişken, keşif amaçlı koddur — test daha bir şey yakalamadan onu üç kez yeniden yazarsınız. Üçüncü ve en pahalı alan, davranışa değil uygulamaya yapışık testlerdir: Ortaya ne çıktığını değil, bir şeyin nasıl gerçekleştiğini doğrulayan, mock ağırlıklı testler. Tek bir hata yakalamadan her yeniden yapılandırmada kırılırlar — teşvik etmek istediğiniz iyileştirmeyi tam olarak cezalandırırlar. Ve son olarak üçüncü taraf ve framework davranışını test etmek: Size ait olmayanı test etmeniz gerekmez; ona güvenir ya da onu kapsüllersiniz.

Bu bölgelerin en kötü yan etkisi flaky testtir — hiçbir şey değişmeden bazen yeşil, bazen kırmızı olan test. Ekibin görmezden gelmeyi öğrendiği tek bir tanesi bile tüm test paketini değersizleştirir: Kırmızı artık hiçbir şey ifade etmiyorsa, hiçbir test koruma sağlamaz.

Önerimiz: Bu bölgelerde bilinçli olarak testten vazgeçin; bir testin gerekli olduğu yerde ise uygulamayı değil davranışı doğrulayın. Bedeli, kapsam oranının düşmesi ve bunun neden iyi olduğunu açıklamak zorunda kalmanızdır. Pahalı bir yan etkisi olan önemsiz kodda farklı karar veririz — basit ama gerçek para hareket ettiren bir adaptör gibi; o zaman önemsizliği değil, arkasındaki pahalı etkiyi test ederiz.

Değen ile zararlı arasındaki sınır şöyle özetlenebilir:

Kod türüHata maliyetiDeğişkenlikÖneri
Çekirdek alan mantığı ve hesaplamalaryüksekdüşüktest edin — en iyi ROI
Dışa dönük kamuya açık sözleşmeleryüksekdüşüksözleşme testleri
Dikiş yerleri: veritabanı, kuyruk, üçüncü taraf servisyüksekortaentegrasyon testleri
Yeniden üretilmiş bugyüksek—regresyon testi olarak sabitleyin
Keşif amaçlı, değişken kodortayükseksonra, istikrar kazandığında
Mantık içermeyen glue ve bağlantı kodudüşük—pek gerekmez
Üçüncü taraf ve framework davranışı——kendiniz test etmeyin

Unit, entegrasyon ve uçtan uca

Üç seviye bir sıralama değil, maliyetin güvenle takasıdır. Her biri başka bir şeyi doğrular, her biri başka bir noktada yalan söyler.

SeviyeDoğruladığıHızBakım maliyetiÖzellikle yakaladığıYalan söylediği durum
Unitizole bir birimçok hızlıdüşük (davranış testlerinde)mantık hataları, sınır durumlarıçok fazla şey mock'landığında
Entegrasyondikiş yerlerindeki etkileşimortaortaDB, kuyruk, üçüncü taraf servisteki gerçek hatalartest ortamı gerçek ortamdan saptığında
Uçtan ucakullanıcının tüm yoluyavaşyüksek, çoğu zaman istikrarsıztüm zincirin çökmesikapsam çok büyük ve neden belirsiz olduğunda

Unit test ucuz ve hızlıdır, ama gerçekte kırılan entegrasyonu mock'ladığı anda yalan söyler. Uçtan uca (end-to-end) test, bütünün çalıştığına dair en yüksek güvenceyi verir, ama yavaş, istikrarsız ve bakımı pahalıdır. Aradaki entegrasyon testi ise gerçek hataların çoğunun aslında bulunduğu dikiş yerlerini — veritabanı, kuyruk, üçüncü taraf servis — doğrular. Pratikte çoğu zaman en iyi ROI'ye sahiptir ve pratikte en sık ihmal edilendir.

Seviyeler arasında değer ile zarar arasındaki farkı belirleyen bir karar vardır: ne kadarını sahte nesnelerle değiştirdiğiniz. Bir test double — bir mock, bir stub — hız ve izolasyon satın alır, ama her sahte nesne gerçek parçanın nasıl davrandığına dair bir varsayımdır ve tam da bu varsayım yanlış olabilir. Veritabanını mock'layan, veritabanını değil, veritabanına dair kendi tasavvurunu test eder. Pratik kural yine ekonomiyi izler: yavaş, pahalı ya da deterministik olmayan kenarlar için sahte nesneler; riski tam da etkileşimlerinin taşıdığı yerde gerçek bağımlılıklar. Ne kadar çok mock'larsanız test o kadar hızlı — ve o kadar dürüst olmayan — bir hâle gelir.

Uçtan uca Entegrasyon Unit az · yavaş · pahalı çok · hızlı · ucuz

Şema: Biçim dogmayı değil riski izler — sık görülen tersine çevrilmiş hâl (çok E2E, az unit) bir anti-pattern'dir.

Önerimiz: Karışımı riskin bulunduğu yere göre biçimlendirin ve entegrasyon seviyesine, yerleşik inanışların önerdiğinden daha fazla ağırlık verin. Bedeli, entegrasyon testlerinin gerçeğe yakın bir ortama — gerçek veritabanı, gerçek kuyruk — ihtiyaç duyması ve bunun kurulum ve çalışma süresi maliyeti getirmesidir. Riski neredeyse tamamen saf mantıkta yatan ve dikiş yerleri önemsiz olan bir uygulamada farklı karar veririz; orada ağırlık haklı olarak aşağıya, unit testlere kayar.

Karakterizasyon testleri

Bazen artık kimsenin anlamadığı ama yine de değiştirilmesi gereken bir kodla karşı karşıya kalırsınız. Burada özel bir test türü yardımcı olur: karakterizasyon testi. Kodun ne yapması gerektiğini tarif etmez, ne yaptığını — tuhaflıklarıyla birlikte — kayda geçirir. Bir kalite hükmü değil, bir güvenlik ağıdır: Bir değişiklikten sonra davranış saparsa, üretim fark etmeden önce o alarm verir. Çoğu zaman, mevcut kodun çıktılarını çok sayıda gerçek girdi üzerinden kaydederek ve her değişiklikte bu kayıtla karşılaştırarak üretilir — kimsenin beklenen sonucu elle formüle etmesine gerek kalmadan sapmaları görünür kılan bir karşılaştırma. Kazanç tam olarak budur: Henüz kendiniz anlamadığınız bir davranışı güvence altına alabilirsiniz.

Ekonomik açıdan karakterizasyon testlerinin kendine özgü bir yanı vardır. Değişiklik anında değerleri çok yüksektir — aksi hâlde fazla tehlikeli olacak bir dönüşümü mümkün kılarlar. Ama bunlar temel değil, iskeledir: Eski kod değiştirildiğinde çoğu zaman yeniden kaldırılabilirler, çünkü zaten kalması istenmeyen bir davranışı sabitlerler. Onları sonsuza dek değil, dönüşüm için inşa edersiniz.

Önerimiz: Anlaşılmamış kodu, ona dokunmadan önce karakterizasyon testleri altına alın ve bu testleri geçici bir iskele olarak görün. Bedeli, test ettiği davranışı değiştirmek istediğiniz testlere emek harcamanızdır. Eski davranışın kanıtlanabilir biçimde yanlış olduğu ve kimsenin ona dayanmadığı durumda farklı karar veririz — o zaman hatayı dondurmazsınız, onu bilinçli olarak düzeltir ve sapmayı belgelersiniz.

Modernizasyon sırasında test

Eski bir sistemin adım adım değiştirilmesinde testler belirleyici güvenlik ağıdır — ama yalnızca doğru kullanıldıklarında. “Önce her şeyi sonradan test edelim” cazibesi pahalıdır ve çoğu zaman boşunadır: Zaten değiştirmek istediğiniz kod için testlere yatırım yaparsınız. Doğru olan, tüm sistemi değil, tam olarak bir sonraki adımda taşıyacağınız dilimi test altına almaktır.

Burada iki şey ekonomik açıdan belirleyicidir. Birincisi ayrım: Taşıma ve davranış değişikliği ayrı tutulur; aksi hâlde hiçbir test bir sapmanın kasıtlı mı yoksa hata mı olduğunu söyleyemez. İkincisi, çalışma zamanında bir test olarak paralel işletim — yeni olan bağlayıcı hâle gelmeden önce eski ve yeniyi birlikte çalıştırıp sonuçları karşılaştırmak. Böylece doğruluk, önceden büyük bir test paketi yazmadan gerçek trafik üzerinde kanıtlanır.

Önerimiz: Modernizasyon sırasında tam olarak taşınan dilimi test edin ve paralel işletimi süregelen bir karşılaştırma olarak kullanın. Bedeli, karşılaştırma süresince çift çalıştırma ve taşıma ile iyileştirmeyi karıştırmama disiplinidir. Çift çalıştırmanın güvenle tekrarlanamayacak yan etkileri olacağı yerde — örneğin ödemeler — farklı karar veririz; orada canlı yerine kaydedilmiş trafiğe karşı karşılaştırma yapılır.

Asenkron sistemleri test etmek

Asenkron sistemler en zor durumdur, çünkü sonucu senkron olarak doğrulayamazsınız: Bir mesaj gönderirsiniz ve bir noktada bir şey olur. Bunu uzun uçtan uca testler ve araya serpiştirilmiş bekleme süreleriyle doğrulayan, tam da artık kimsenin ciddiye almadığı istikrarsız testleri elde eder. Asenkron sistemlerdeki pahalı hatalar zaten başarılı senaryoda değil, kenarlardadır: çift teslimat, yeniden deneme, sıralama, bir alıcının çökmesi.

Ekonomik yaklaşım sorunu parçalara ayırır. Her alıcıyı temsili mesajlarla izole olarak test edersiniz; bir gönderenin alıcıyı sessizce bozmaması için mesajların sözleşmesini doğrularsınız; ve pahalı yolları hedefli olarak test edersiniz — çift teslimatta idempotency, yeniden deneme ve hata durumunda davranış. Bekleme sürelerine güvenmek yerine zamanı ve teslimatı test içinde deterministik hâle getirirsiniz. Tüm asenkron zincir boyunca her kombinasyonu değil, yalnızca tek kritik yolu test edersiniz.

Önerimiz: Tüm asenkron zinciri uçtan uca doğrulamak yerine alıcıları, mesaj sözleşmelerini ve pahalı hata yollarını tek tek ve deterministik olarak test edin. Bedeli, hiçbir tekil testin “her şey birlikte çalışıyor” konusunda tam kesinlik vermemesidir — bu kesinliği kritik yol üzerindeki az sayıda, hedefli entegrasyon testiyle satın alırsınız. Sonucun hemen belli olduğu senkron işlemede farklı karar veririz; orada basit, doğrudan test daha ucuz seçimdir.

Sık yapılan hatalar

Getiriyi negatife çeviren, hep aynı kalıplardır:

  • Hedef olarak kapsam — kendi başına amaca dönüşen ve kırılgan testleri ödüllendiren bir girdi büyüklüğü.
  • Uygulamaya yapışık olan ve hata yakalamadan her yeniden yapılandırmada kırılan testler.
  • Ters piramit: çok sayıda yavaş uçtan uca test, az sayıda hızlı unit test.
  • Kırmızı artık hiçbir şey ifade etmeyene ve tüm test paketi görmezden gelinene kadar hoş görülen istikrarsız testler.
  • Size hiç ait olmayan üçüncü taraf ve framework davranışını test etmek.
  • Paranın, verinin ya da güvenliğin tehlikede olduğu yerlerde test olmaması.
  • Yalnızca değiştirilen dilimi güvence altına almak yerine legacy kodu gelişigüzel sonradan test etmek.
  • Asenkron olanı bekleme süreleriyle test etmek ve istikrarsızlığa (flakiness) şaşırmak.
  • Nedeni gidermek yerine kırmızı bir testi silmek.

Karar kontrol listesi

Bir ekibin bir test yazmadan önce sorabileceği sorular. Bunlar hüküm değil, teşhis sorularıdır.

  • Bu noktada bir hata pahalı olur muydu — para, veri, güvenlik, geri alınamaz olan? Testin değeri hata maliyetiyle artar.
  • Bu test gelecek ay da geçerli olacak mı, yoksa davranış sürekli mi değişiyor? Değişkenlik getiriyi yer.
  • Test davranışı mı, uygulamayı mı doğruluyor? Nasıl'ı doğrulayan, her yeniden yapılandırmanın bedelini öder.
  • Riski yakalayan en ucuz seviye bu mu — unit, entegrasyon ya da uçtan uca? Her güvence en pahalı testi gerektirmez.
  • Gerçek risk dikiş yerlerinde mi — ve onları yeterince test ediyor muyuz? Entegrasyon en sık ihmal edilendir.
  • Bir test istikrarsızsa: Onu görmezden gelmek yerine nedeni gideriyor ya da siliyor muyuz? Hoş görülen tek bir flaky test hepsini değersizleştirir.
  • Devralınan kodda: Mevcut davranış, onu değiştirmeden önce sabitlendi mi? Gözlemleyemediğiniz şeyi güvenle değiştiremezsiniz.
  • Değeri mi — güvenli hâle getirilmiş değişiklik — yoksa kapsam gibi bir girdi büyüklüğünü mü ölçüyoruz? Hedef yüzde değil, risktir.

Sıkça Sorulan Sorular

Hangi test kapsamını hedeflemeliyiz? Belirli bir oranı değil. Kapsam, ne kadar riskin güvence altına alındığını değil, ne kadar kodun çalıştırıldığını ölçer — önemsiz kod üzerinde yüksek bir değer hiçbir şey satın almaz. Bir yüzdeyi değil, güvence altına alınmış riski hedefleyin; sayı bir hedef değil, bir yan üründür.

Test güdümlü geliştirme zorunlu mu? Hayır. TDD bir kalite mührü değil, bir çalışma akışıdır. Davranışı önceden net biçimde formüle edebildiğiniz yerde yardımcı olur, tasarımı hâlâ aradığınız yerde ise engel olur. Onu bir buyruk olarak değil, bir araç olarak kullanın.

Testler bizi yavaşlatmaz mı? Kötü testler evet — uygulamaya yapışık olan ve her değişiklikte kırılanlar. İyi testler ise hızlandırır, çünkü değişikliği güvenli kılar: Bir ağ, pahalı bir şeyin kırılıp kırılmadığını hemen söylediğinde daha hızlı değişiklik yaparsınız. Fark miktarda değil, seçimdedir.

Kaç uçtan uca teste ihtiyacımız var? Kritik kullanıcı yollarını kapsayacak kadar az. Uçtan uca testler pahalı ve istikrarsızdır; değerleri her kombinasyonu doğrulamakta değil, en önemli yolların bir bütün olarak çalıştığından emin olmaktadır. Bunun altındaki her şey daha ucuz seviyelere aittir.

Legacy kodu sonradan eksiksiz test etmeli miyiz? Hayır. Değiştirmek istediğiniz kodu sonradan eksiksiz test etmek boşa giden bir yatırımdır. Karakterizasyon testleriyle tam olarak bir sonraki adımda değiştireceğiniz parçaları güvence altına alın ve geri kalanını sırası gelene kadar bırakın.

Eventual consistency nasıl test edilir? Bekleme süreleri ve uzun zincirlerle değil, parçalara ayırarak: alıcılar izole olarak, mesaj sözleşmeleri ve hedefli olarak pahalı hata yolları — çift teslimat, yeniden deneme, çökme. Zamanlamaya umut bağlamak yerine zamanı ve teslimatı test içinde deterministik hâle getirirsiniz.

İleri okuma

Temel, Batunet Engineering Method'tur: hataların pahalı olduğu yerde test etmek, en zor yolu önce kanıtlamak, hata durumu için tasarlamak.


Bir test ne bir özen kanıtıdır ne de boşa giden bir emek. Belirli bir değişikliğin güvenli kalması gerektiğine dair bir bahistir. İyi ekipler nadiren bahse girer, ama girdiklerinde doğru oynarlar.

Referans verilen bileşenler

Bu alanda somut bir projeniz mi var?

Referans rehberleri düşünce yapımızı yansıtır. Kendi sisteminizi doğrudan yönetimle konuşabilirsiniz.