---
title: 'Davranış Odaklı Test'
source: 'https://academia.sh/tr/kurslar/java-ekosistem/davranis-odakli-test'
course: 'Derleme, Test ve Ekosistem'
language: tr
updated: '2026-08-23T14:25:06+00:00'
license: 'CC BY-SA 4.0'
---

# Davranış Odaklı Test

Dört satırlık bir senaryo metni bir adım haritasına karşı çalıştırılıyor; haritada karşılığı olmayan adım bir koşumda sessizce atlanıyor, başka bir koşumda programı durduruyor. Aynı dört adım tam eşleştiğinde bile, kontrol adımlarının iddiası kaldırılmış bir haritayla koşturulunca yanlış bir değer üzerinden yine 'geçti' diyor.

Önceki derste sınanan sistem büyüdü: birim kurulumunda sahtelenen bir bağımlılık gerçek
gerçekleştirimiyle geri geldi ve testin gördüğü sınıf yolu iki tipe çıktı. Bu derste
büyüyen taraf farklı: sınanan kod değil, testin **kendisi** düzyazıya yaklaşıyor. Bir
senaryo, sıradan cümlelerle yazılmış bir adım listesidir — "depoya 10 birim eklendi",
"depo miktarı 7 olmalı" gibi — ve bu cümlelerin adım haritasında çalıştırılabilir bir
karşılığı olması beklenir. Soru şu: metindeki dört adımın kaçının gerçek bir karşılığı
var, karşılığı olmayan adım koşumu nasıl etkiliyor, ve adımların tümü eşleşse bile bu
senaryonun **doğru** çalıştığı anlamına mı geliyor?

Senaryo dilinin çekiciliği, teknik olmayan bir okurun da adımları anlayabilmesindedir —
"depoya 10 birim eklendi" cümlesi Java bilmeyen biri için de bir anlam taşır. Ama bu
okunabilirlik bir bedel taşır: düzyazı, derleyicinin denetleyebileceği bir sözdizimi
değildir. Bir yöntem adı yanlış yazıldığında derleyici hemen durur; bir senaryo satırı
yanlış yazıldığında ya da hiç uygulanmadığında, bunu fark eden yalnız koşumun kendisidir.
Bu ders, o farkın nasıl fark edildiğini ve fark edilmemesinin ne anlama geldiğini
koşturarak gösteriyor.

Davranış odaklı geliştirme kavramı M21/K02 Birim Testi ve Test Odaklı Geliştirme kursunda
kuruldu ve burada yeniden tanıtılmaz. Bu dersin eklediği tek soru, senaryo metninin
bildirdiği adımlar ile adım haritasında gerçekten bulunan adımlar arasındaki **eşleşmedir**.

Bu soru, aslında dersin başından beri sorduğumuz sorunun bir varyasyonu. Birinci derste
soru "bu tip test sınıf yolunda var mı" idi ve tip somut, derlenmiş bir `.class` dosyasıydı.
Beşinci derste tip yerini bir cümleye bırakıyor: senaryo metnindeki her satır, adım
haritasında kendisini karşılayacak bir davranışa ihtiyaç duyuyor. Fark bir adlandırma
sorunundan ibaret değil — bir tipin sınıf yolunda bulunup bulunmadığını derleyici bize
söyler, ama bir metin satırının bir davranışla eşleştiğini kimse bize söylemez; bu ders o
eşleşmeyi elle kurup elle sayıyor.

## Senaryo Bir Bildirimdir, Adım Haritası Karşılığını Verir

- **TS21.** Senaryo adımları burada düz dizeler olarak eşleştirilir (`Map<String, ...>`).
  Gerçek çerçevelerin örüntü eşleme, düzenli ifadeyle adım tanımlama ve parametre çıkarma
  mekanizması burada kurulmaz.
- **TS22.** Bir adımın "eşleşmesi", metninin haritada birebir bir anahtarla bulunmasıdır.
  Bu, adımın **doğru** çalıştığını değil, yalnız çalıştırılabilir bir karşılığı olduğunu
  gösterir — ikisi ayrı sorulardır.
- **TS23.** "Sessiz" ve "durduran" iki ayrı koşum stratejisi burada elle yazılır. Gerçek
  çerçevelerin bu ikisi arasında hangisini varsayılan seçtiği ya da nasıl yapılandırıldığı
  burada modellenmez.

Senaryo metni dört satırdan oluşuyor ve bir `record` dizisi olarak bildiriliyor — üçüncü
derste veri kümesinin bildirilme biçimiyle aynı yöntem, burada veri yerine düzyazı adımlar
taşıyor. Adım haritası ise her satırın metnini bir çalıştırılabilir gövdeye bağlıyor.
Aşağıdaki `eksikHarita` dördüncü adımın metnini hiç içermiyor — bilinçli bir eksiklik.
`sessizKosum` karşılığı bulunamayan adımı atlayıp devam ediyor, `durduranKosum` aynı
durumda bir istisna fırlatıp koşumu kesiyor.

Haritanın kendisi bir `LinkedHashMap` — sıradan bir eşleme değil, eklenme sırasını koruyan
bir eşleme. Bu, senaryonun kendi sırasını değil, haritanın **kayıt** sırasını koruyor;
adımların hangi sırayla çalıştığına haritanın kendisi karar vermiyor, o kararı `METIN`
dizisindeki sıra veriyor. Sıra korumasının burada tek pratik faydası, iki haritayı yan
yana okurken adımların hangi sırayla tanımlandığını görebilmek — koşumun kendisi `METIN`
dizisini baştan sona dolaşıyor, haritanın iç sırasına bakmıyor.

Adım haritasının kendisi, ilk derste kurulan test sınıf yolu kavramının doğal bir uzantısı.
`eksikHarita` ve `bosIddialiHarita` üretim kodunun hiçbir yerinde geçmiyor; ikisi de yalnız
test tarafının bildiği, test tarafının koştuğu birer eşleme. Senaryo metninin kendisi de
öyle — `METIN` dizisi üretim kodunun okuduğu bir veri değil, testin okuduğu bir bildirim.
Bu derste yeni olan, bu bildirimin **düzyazı** biçiminde durması ve karşılığının bir tip
adı değil bir dize anahtarı olmasıdır.

```java
// Senaryo.java — senaryo metni bir bildirimdir, adim haritasinda karsiligi bulunamayan adim sessiz mi kaliyor durduruyor mu
import java.util.*;
import java.util.function.Consumer;

public class Senaryo {

    record Adim(String metin) {}

    static final Adim[] METIN = {
        new Adim("depoya 10 birim eklendi"),
        new Adim("depodan 3 birim azaltildi"),
        new Adim("depo miktari 7 olmali"),
        new Adim("depo miktari eksiye dusmemeli"),
    };

    // -- adim haritasi eksik: dorduncu adimin hicbir kaydi yok --------------------
    static Map<String, Consumer<int[]>> eksikHarita() {
        Map<String, Consumer<int[]>> h = new LinkedHashMap<>();
        h.put("depoya 10 birim eklendi", d -> d[0] += 10);
        h.put("depodan 3 birim azaltildi", d -> d[0] -= 3);
        h.put("depo miktari 7 olmali", d -> { if (d[0] != 7) throw new AssertionError("miktar 7 degil: " + d[0]); });
        return h;
    }

    // -- adim haritasi tam: dordu de kayitli, ama kontrol adimlarinin iddiasi kaldirilmis --
    static Map<String, Consumer<int[]>> bosIddialiHarita() {
        Map<String, Consumer<int[]>> h = new LinkedHashMap<>();
        h.put("depoya 10 birim eklendi", d -> d[0] += 10);
        h.put("depodan 3 birim azaltildi", d -> d[0] -= 2); // kasitli hata: 3 degil 2 azaltiyor
        h.put("depo miktari 7 olmali", d -> {});            // iddia kaldirilmis
        h.put("depo miktari eksiye dusmemeli", d -> {});    // iddia kaldirilmis
        return h;
    }

    static void sessizKosum(Adim[] senaryo, Map<String, Consumer<int[]>> harita, int[] durum) {
        int eslesen = 0;
        for (Adim a : senaryo) {
            Consumer<int[]> uygulama = harita.get(a.metin());
            if (uygulama == null) { System.out.println("atlaniyor    : " + a.metin()); continue; }
            uygulama.accept(durum);
            eslesen++;
        }
        System.out.println("eslesen adim : " + eslesen + "/" + senaryo.length);
        System.out.println("sonuc        : gecti, depo=" + durum[0]);
    }

    static void durduranKosum(Adim[] senaryo, Map<String, Consumer<int[]>> harita, int[] durum) {
        int eslesen = 0;
        for (Adim a : senaryo) {
            Consumer<int[]> uygulama = harita.get(a.metin());
            if (uygulama == null) throw new IllegalStateException("adimin karsiligi yok: " + a.metin());
            uygulama.accept(durum);
            eslesen++;
        }
        System.out.println("eslesen adim : " + eslesen + "/" + senaryo.length);
        System.out.println("sonuc        : gecti, depo=" + durum[0]);
    }

    public static void main(String[] args) {
        System.out.println("-- eksik harita, sessiz kosum --");
        sessizKosum(METIN, eksikHarita(), new int[]{0});

        System.out.println("-- eksik harita, durduran kosum --");
        try {
            durduranKosum(METIN, eksikHarita(), new int[]{0});
        } catch (IllegalStateException e) {
            System.out.println("durdu        : " + e.getMessage());
        }

        System.out.println("-- tam harita, iddiasi kaldirilmis kontrol adimlari --");
        sessizKosum(METIN, bosIddialiHarita(), new int[]{0});
    }
}
```

```
-- eksik harita, sessiz kosum --
atlaniyor    : depo miktari eksiye dusmemeli
eslesen adim : 3/4
sonuc        : gecti, depo=7
-- eksik harita, durduran kosum --
durdu        : adimin karsiligi yok: depo miktari eksiye dusmemeli
-- tam harita, iddiasi kaldirilmis kontrol adimlari --
eslesen adim : 4/4
sonuc        : gecti, depo=8
```

İlk iki koşum aynı `eksikHarita`'yı, aynı dört satırlık senaryoyu kullanıyor; fark yalnız
karşılığı bulunamayan adıma verilen tepkide. `sessizKosum` dördüncü adımı atlıyor, üç
adımı çalıştırıyor, "3/4" diyor ve "gecti" ile bitiriyor — senaryo metninde dört satır
olduğu hâlde, koşum yalnız üçünü gerçekten işletti. `durduranKosum` ise aynı eksikliği bir
istisnaya çeviriyor: hangi adımın metninin karşılıksız kaldığı doğrudan hata mesajında
görünüyor, ve koşum orada duruyor, kalan adımlar hiç işletilmiyor.

Bu iki strateji arasındaki fark, kursun daha önceki derslerinde görülen sessiz/koşum
ayrımının senaryo metni düzeyindeki karşılığı. Sessiz strateji, eksik bir adımı fark
edilmeden geçiştiriyor — üç adımlık bir senaryo, dört adımlık bir senaryo gibi raporlanıyor,
"3/4" satırı okunmazsa hiç görünmüyor. Durduran strateji ise eksikliği bir koşum hatasına
çeviriyor ve neyin eksik olduğunu adının içine yazıyor. Hiçbiri "doğru" strateji değil;
biri yazım hatası yapılmış bir adımı erken yakalar, öteki senaryonun geri kalanının hâlâ
çalışabildiğini görmeyi sağlar. Seçim, senaryo metnini kimin yazdığına ve o metnin ne
sıklıkla değiştiğine bağlıdır.

Sessiz stratejinin riski, "3/4" satırının gözden kaçmasının hiç zor olmamasıdır. Bir senaryo takımı
onlarca satırlık metinler biriktirdiğinde, her koşumun ürettiği eşleşme oranını tek tek
okumak gerçekçi değildir; çoğu rapor yalnız "geçti" ya da "düştü" özetini gösterir, eşleşme
sayısını göstermez. Bu durumda sessiz strateji, hiç yazılmamış bir adımı hiç fark
edilmeden aylarca taşıyabilir — senaryo metni bir davranışı bildiriyor gibi görünür, ama o
davranış hiçbir zaman gerçekten koşmamıştır. Durduran strateji bu riski ortadan kaldırır,
ama karşılığında senaryo metnindeki her küçük yazım farkını (eksik bir boşluk, değişen bir
sayı) bir koşum hatasına çevirir; metin sık değişiyorsa bu, gerçek kusurlardan çok metin
bakımı hatalarını raporlamaya başlar. İki stratejinin birlikte var olması bu yüzden
tesadüfi değil: hangi hatanın erken yakalanması, hangisinin görmezden gelinebilir olduğu bir
mühendislik kararıdır ve senaryo metninin kimin tarafından, ne sıklıkla yazıldığına bağlıdır.

## Adım Sayısının Tam Olması Doğruluğu Göstermez

- **TS24.** Kasıtlı hata — azaltmanın 3 yerine 2 uygulanması — yalnız sınırlayıcı ölçümü
  göstermek için üçüncü koşumda tanıtılır. İlk iki koşum doğru işleyen bir azaltma
  kullanır; üçünün karşılaştırılabilir olması için yalnız tek bir değişken değiştirilir.
- **TS25.** "İddiası kaldırılmış" adım burada boş bir gövdeyle (`d -> {}`) modellenir.
  Adımın haritada bir karşılığı vardır ve eşleşme sayılır, yalnız o karşılık hiçbir şeyi
  denetlemez.

Üçüncü koşum ilk ikisinden iki noktada ayrılıyor. Birincisi, `bosIddialiHarita` dört
adımın dördünü de içeriyor — hiçbir adım atlanmıyor, hiçbir istisna fırlamıyor, eşleşen
adım sayısı "4/4". İkincisi, bu haritadaki azaltma adımı kasıtlı olarak yanlış: 3 yerine
2 azaltıyor. Doğru işleseydi depo miktarı 7 olurdu; bu koşumda 8 kalıyor. `eksikHarita`
kullanan ilk koşumda "depo miktari 7 olmali" adımı gerçek bir kontrol taşıyordu ve yanlış
bir değeri yakalardı. `bosIddialiHarita`'da aynı metin haritada duruyor, eşleşiyor, ama
gövdesi boş — hiçbir karşılaştırma yapmıyor. Sonuç satırı yine "gecti, depo=8" diyor;
"gecti" kelimesi burada yalnızca istisna fırlamadığı anlamına geliyor, değerin doğru
olduğu anlamına gelmiyor.

Bu üçüncü koşumun ilk iki koşumla aynı senaryo metnini paylaşması bilinçli bir tercih.
Metin hiç değişmedi — dört satır, aynı sırayla, aynı kelimelerle. Değişen yalnız o metnin
arkasındaki uygulamadır: bir sürümde üçüncü adım gerçek bir sayı karşılaştırması taşıyordu,
diğerinde aynı adım hiçbir şey yapmıyor. Senaryo metnini okuyan biri bu farkı göremez —
metin ikisinde de birebir aynı satırı taşıyor. Farkı görmenin tek yolu, adım haritasının
kendisini okumak ya da koşturup gerçek değeri gözlemlemektir; metnin kendisi hiçbir zaman
arkasındaki uygulamanın ne yaptığını garanti etmez.

Bu, kursun beşinci payının kapanış gözlemi: eşleşen adım sayısının tam olması —
senaryonun her satırının bir karşılığı olması — senaryonun **doğru çalıştığını**
göstermez. Bir metnin her adımının adım haritasında bir karşılığı bulunması, o karşılığın
içinde gerçekten bir iddia yazılı olduğu anlamına gelmiyor; adım haritasındaki bir giriş,
boş bir gövdeyle de tamamen geçerli bir eşleşme sayılıyor. "4/4 eşleşti" ile "senaryo
doğru çalıştı" iki ayrı önermedir, ve bu ders ikisini aynı koşumda birbirinden ayırarak
gösteriyor: sayı tamken bile bir hata sessizce geçebiliyor.

Bu üç koşumu yan yana koyunca kursun ölçü sorusunun son biçimi ortaya çıkıyor. Önceki
derslerde soru "bu tip hangi sınıf yolunda bulunmak zorunda" biçimindeydi ve tip somut bir
`.class` dosyasıydı. Burada "tip" yerine bir **adım** duruyor, "sınıf yolu" yerine bir
**adım haritası** duruyor, ama soru aynı kalıba oturuyor: bu adımın adım haritasında bir
karşılığı var mı, ve o karşılık gerçekten bir şey mi denetliyor. Senaryo metni bir
bildirimdir; adım haritası ise o bildirimin çalıştırılabilir karşılığıdır, ve ikisi arasında
bir boşluk kaldığında — ister eksik bir kayıt, ister boş bir gövde olarak — o boşluk
metinden okunarak değil, yalnız koşturarak görülür.

Bu payın beş dersi boyunca aynı soru beş ayrı biçimde soruldu. Birinci derste soru bir
çerçeve tipinin test sınıf yolunda bulunup bulunmadığıydı; ikincisinde aynı adı taşıyan
iki gerçekleştirimden hangisinin koşum sınıf yolunda durduğuydu; üçüncüsünde bir kurulumun hangi
kapsamda çalıştığıydı; dördüncüsünde gerçek bir bağımlılığın sınıf yoluna girip
girmediğiydi. Bu son derste soru, bir davranışın adım haritasında bir karşılığı olup
olmadığına indirgendi. Beşinde de ortak olan, sorunun kaynak metinden değil, gerçekten
koşturarak yanıtlanmasıydı — bir tipin, bir kurulumun ya da bir adımın ne yaptığı, yazıldığı
biçimden değil, çalıştırıldığında ürettiği sonuçtan okunuyordu.

Beş dersin de paylaştığı ikinci bir örüntü, "tam" görünen bir sonucun yeterlilik anlamına
gelmemesiydi. Birinci derste tam bir test sınıf yolu bile çerçeve eksikse çöküyordu; ikincide
hatasız tamamlanan bir koşum yanlış bir sayı taşıyordu; üçüncüde geçen bir satır yalnız
sırası uygun düştüğü için geçiyordu; dördüncüde sessiz bir koşum bir sınır ihlalini hiç
görmüyordu. Bu son ders aynı örüntüyü adım sayısı üzerinden tekrarladı: "4/4" görünen bir
senaryo, arkasında hiçbir gerçek kontrol taşımayabiliyordu. Bu tekrar tesadüfi değil —
kursun tezinin kendisi budur: derlenmiş, koşan, "tamam" diyen bir program, hangi soruya
yanıt verdiği söylenmeden okunamaz.

## Özet

- Senaryo metni dört adımlık bir bildirim olarak yazıldı; adım haritası bu adımların
  çalıştırılabilir karşılıklarını verdi.
- Karşılığı bulunamayan bir adım bir koşumda sessizce atlandı (3/4 eşleşti), başka bir
  koşumda bir istisnayla koşumu durdurdu.
- Dört adımın dördü de eşleştiğinde ("4/4"), bu tek başına senaryonun doğru çalıştığını
  göstermedi.
- Kontrol adımlarının iddiası kaldırılmış bir haritayla koşulan senaryo, yanlış bir değer
  (8, beklenen 7) üzerinden yine "gecti" dedi.
- Davranış odaklı geliştirme kavramı M21/K02'de kuruldu; bu derste eklenen tek soru,
  senaryo metni ile adım haritasındaki karşılığı arasındaki eşleşmeydi.

## Sonraki Adım

Bu payın beş dersinde testin gördüğü sınıf yolunu biz kurduk: hangi tipin, hangi adımın
o yolda duracağını baştan biliyorduk, çünkü hepsini kendi ellerimizle yazdık — sahte
tipin adını da, adım haritasının anahtarlarını da testi yazan taraf belirledi. Sıradaki
konu bunun tam tersini soruyor. Bir günlükleme çağrısı, kendisini karşılayacak
gerçekleştirimin adını hiç yazmaz — kaynak metinde yalnız bir cepheye seslenir, hangi
sınıfın o çağrıyı karşılayacağını belirtmez. O adın koşum sınıf yoluna nasıl girdiği, kim koyduğu
ve iki gerçekleştirim birden bulunduğunda hangisinin seçildiği, sıradaki konunun sorusu.
