---
title: 'Davranış Odaklı Geliştirme'
source: 'https://academia.sh/tr/kurslar/birim-testi/davranis-odakli-gelistirme'
course: 'Birim Testi ve Test Odaklı Geliştirme'
language: tr
updated: '2026-08-17T18:10:54+00:00'
license: 'CC BY-SA 4.0'
---

# Davranış Odaklı Geliştirme

Kuralların alan diliyle yazılmış örnek tablolarıyla tanımlanması, tablo için bir biçim ve çözümleyici yazılması ve tablodan üretilen veri güdümlü testlerle döngünün sürdürülmesi.

Önceki dersteki yedi test, kuralları ayrı ayrı cümlelerle anlattı ve her cümle bir kod
bloğu oldu. Kurallar çoğaldıkça bu yazım tekrar üretir: aynı düzenek, aynı çağrı, yalnız
girdi ve beklenen sonuç değişir. Daha önemlisi, kuralın kendisi koda gömülü kalır. Ödünç
kurallarını belirleyen kişi kütüphane görevlisidir, ama kuralların yazılı olduğu yer bir
test dosyasıdır ve o dosya görevliyle konuşurken açılamaz.

**Davranış odaklı geliştirme** (behavior driven development) bu boşluğu kapatmayı hedefler.
Döngü aynı döngüdür — kırmızı, yeşil, yeniden düzenle — ama konuşmanın birimi bir test
işlevi değil, alan diliyle yazılmış bir **örnektir**. Örnek üç parça taşır: verilen bir
başlangıç durumu, yapılan bir işlem ve beklenen sonuç. Bu üçlü, birinci dersteki hazırla,
uygula ve doğrula bölümlerinin alan diline çevrilmiş hâlidir.

## Örnek Tablosunun Biçimi

Örneklerin yazılacağı biçim bir standarda bağlı değildir; taşıması gereken tek şey, hem
görevlinin okuyabilmesi hem de bir programın ayrıştırabilmesidir. Aşağıdaki biçim iki
satır türü tanır: bir kural başlığı ve o kurala ait örnekler.

```bash
cat > ornekler.txt <<'ORNEK'
# yenileme sozlesmesi — her kural, kendisini gosteren orneklerle tanimlidir
kural: Yenileme son tarihi bugunden itibaren uye turunun odunc suresi kadar ileri alir
  ornek: uyeTuru=ogrenci bugun=1020 sonGun=1028 -> sonGun=1048
  ornek: uyeTuru=uye bugun=1020 sonGun=1024 -> sonGun=1034

kural: Rezerve edilmis kitap yenilenemez
  ornek: bugun=1020 sonGun=1028 rezerveEdildi=evet -> hata=rezerve edilmis

kural: Bir odunc en cok iki kez yenilenebilir
  ornek: bugun=1020 sonGun=1028 yenilemeSayisi=1 -> yenilemeSayisi=2
  ornek: bugun=1020 sonGun=1028 yenilemeSayisi=2 -> hata=en cok 2 kez

kural: Gecikmis odunc yenilenemez, son gunde yapilan yenileme kabul edilir
  ornek: bugun=1029 sonGun=1028 -> hata=gecikmis odunc
  ornek: bugun=1028 sonGun=1028 -> sonGun=1056
ORNEK
```

Ok işaretinin solu verilen durumdur, sağı beklenen sonuçtur; yapılan işlem tektir ve
dosyanın adından bellidir. Belirtilmeyen alanlar varsayılan değerlerini alır, böylece her
örnek yalnız kendi kuralıyla ilgili alanları gösterir.

## Çözümleyici

Biçim kendi kendine çalışmaz; onu veri yapısına çeviren bir çözümleyici gerekir. Elli
satırın altında bir çözümleyici bu iş için yeterlidir ve tanımadığı satırda susmak yerine
hata vermesi önemlidir — sessizce atlanan bir satır, hiç koşmayan bir kural demektir.

```js
// cozumleyici.mjs — ornek dosyasini kural ve ornek listesine cevirir
const deger = (metin) => {
  if (metin === 'evet') return true;
  if (metin === 'hayir') return false;
  return /^-?\d+$/.test(metin) ? Number(metin) : metin;
};

const alanlar = (parca) => Object.fromEntries(
  parca.trim().split(/\s+/).filter(Boolean).map((ikili) => {
    const [ad, ...kalan] = ikili.split('=');
    return [ad, deger(kalan.join('='))];
  }),
);

export function cozumle(metin) {
  const kurallar = [];
  for (const ham of metin.split('\n')) {
    const satir = ham.trim();
    if (satir === '' || satir.startsWith('#')) continue;
    if (satir.startsWith('kural:')) {
      kurallar.push({ baslik: satir.slice(6).trim(), ornekler: [] });
      continue;
    }
    if (satir.startsWith('ornek:')) {
      if (kurallar.length === 0) throw new Error(`kuralsiz ornek: ${satir}`);
      const govde = satir.slice(6);
      const [girdi, cikti] = govde.split('->');
      if (cikti === undefined) throw new Error(`ok isareti eksik: ${satir}`);
      const beklenen = cikti.trim();
      kurallar.at(-1).ornekler.push({
        metin: govde.trim(),
        girdi: alanlar(girdi),
        hata: beklenen.startsWith('hata=') ? beklenen.slice(5) : undefined,
        sonuc: beklenen.startsWith('hata=') ? undefined : alanlar(beklenen),
      });
      continue;
    }
    throw new Error(`taninmayan satir: ${satir}`);
  }
  return kurallar;
}
```

Sınanacak kitaplık, önceki dersin dört kuralını uygulayan sürümdür.

```js
// yenileme.mjs — dort kuralin tamami
export const KURALLAR = { ogrenci: { oduncGun: 28 }, uye: { oduncGun: 14 } };
export const EN_COK_YENILEME = 2;
export const SINIR_ILETISI = `en cok ${EN_COK_YENILEME} kez yenilenebilir`;

export function yenile(kayit, bugun) {
  if (kayit.rezerveEdildi) throw new Error('rezerve edilmis kitap yenilenemez');
  if (kayit.yenilemeSayisi >= EN_COK_YENILEME) throw new Error(SINIR_ILETISI);
  if (bugun > kayit.sonGun) throw new Error('gecikmis odunc yenilenemez');
  return {
    ...kayit,
    sonGun: bugun + KURALLAR[kayit.uyeTuru].oduncGun,
    yenilemeSayisi: kayit.yenilemeSayisi + 1,
  };
}
```

## Tablodan Üretilen Testler

Testler artık elle yazılmaz; çözümlenmiş tablodan üretilir. Bu yazım biçimine **veri güdümlü
test** (data driven test) denir: test gövdesi tektir, girdi kümesi veriden gelir.

```js
// ornek.test.mjs — ornek tablosundan uretilen veri gudumlu testler
import { readFileSync } from 'node:fs';
import { describe, test } from 'node:test';
import assert from 'node:assert/strict';
import { cozumle } from './cozumleyici.mjs';
import { yenile } from './yenileme.mjs';

const VARSAYILAN = {
  uyeNo: 'U-17', uyeTuru: 'ogrenci', sonGun: 1028, yenilemeSayisi: 0,
  rezerveEdildi: false, siradakiUye: 'U-99',
};

const metin = readFileSync(new URL('./ornekler.txt', import.meta.url), 'utf8');

for (const kural of cozumle(metin)) {
  describe(kural.baslik, () => {
    for (const ornek of kural.ornekler) {
      test(ornek.metin, () => {
        const { bugun, ...ustuneYaz } = ornek.girdi;
        const kayit = { ...VARSAYILAN, ...ustuneYaz };

        if (ornek.hata !== undefined) {
          assert.throws(() => yenile(kayit, bugun), new RegExp(ornek.hata));
          return;
        }

        const yeni = yenile(kayit, bugun);
        for (const [alan, beklenen] of Object.entries(ornek.sonuc)) {
          assert.equal(yeni[alan], beklenen, `${alan} uyusmuyor`);
        }
      });
    }
  });
}
```

```sh
node --test --test-reporter=tap ornek.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail))'
```

```
    ok 1 - uyeTuru=ogrenci bugun=1020 sonGun=1028 -> sonGun=1048
    ok 2 - uyeTuru=uye bugun=1020 sonGun=1024 -> sonGun=1034
ok 1 - Yenileme son tarihi bugunden itibaren uye turunun odunc suresi kadar ileri alir
    ok 1 - bugun=1020 sonGun=1028 rezerveEdildi=evet -> hata=rezerve edilmis
ok 2 - Rezerve edilmis kitap yenilenemez
    ok 1 - bugun=1020 sonGun=1028 yenilemeSayisi=1 -> yenilemeSayisi=2
    ok 2 - bugun=1020 sonGun=1028 yenilemeSayisi=2 -> hata=en cok 2 kez
ok 3 - Bir odunc en cok iki kez yenilenebilir
    ok 1 - bugun=1029 sonGun=1028 -> hata=gecikmis odunc
    ok 2 - bugun=1028 sonGun=1028 -> sonGun=1056
ok 4 - Gecikmis odunc yenilenemez, son gunde yapilan yenileme kabul edilir
# tests 7
# pass 7
# fail 0
```

Üçüncü dersteki gözlem burada en güçlü hâline ulaşıyor: geçen testlerin listesi bir kural
belgesidir. Girintisiz satırlar kuralları, girintili satırlar o kuralı gösteren örnekleri
verir. Bu çıktı ile örnek dosyası aynı metni taşır — biri kaynağın, diğeri koşumun
ifadesidir.

## Kırmızı Adım Artık Bir Metin Satırıdır

Görevliyle yapılan bir konuşmadan yeni bir kural çıktığını varsayalım: rezerve edilmiş bir
kitap, rezervasyon sırasındaki ilk üye kitabı elinde tutan üyenin kendisiyse yenilenebilir.
Bu kuralın kırmızı adımı artık kod yazmayı gerektirmez.

```bash
cat >> ornekler.txt <<'ORNEK'

kural: Rezervasyon sirasindaki ilk uye oduncu elinde tutan uyeyse yenileme kabul edilir
  ornek: bugun=1020 sonGun=1028 rezerveEdildi=evet siradakiUye=U-17 -> sonGun=1048
ORNEK
```

```sh
node --test --test-reporter=tap ornek.test.mjs | grep -E '^ *(not ok|# (tests|pass|fail))'
```

```
    not ok 1 - bugun=1020 sonGun=1028 rezerveEdildi=evet siradakiUye=U-17 -> sonGun=1048
not ok 5 - Rezervasyon sirasindaki ilk uye oduncu elinde tutan uyeyse yenileme kabul edilir
# tests 8
# pass 7
# fail 1
```

Test dosyasına tek satır eklenmedi. Kırmızı adımı başlatan şey, alan diliyle yazılmış iki
satırlık bir metindir. Yeşil adım ise yine koddadır.

```js
// yenileme.mjs — surum 2: rezervasyon sirasindaki ilk uye kurali eklendi
export const KURALLAR = { ogrenci: { oduncGun: 28 }, uye: { oduncGun: 14 } };
export const EN_COK_YENILEME = 2;
export const SINIR_ILETISI = `en cok ${EN_COK_YENILEME} kez yenilenebilir`;

export function yenile(kayit, bugun) {
  if (kayit.rezerveEdildi && kayit.siradakiUye !== kayit.uyeNo) {
    throw new Error('rezerve edilmis kitap yenilenemez');
  }
  if (kayit.yenilemeSayisi >= EN_COK_YENILEME) throw new Error(SINIR_ILETISI);
  if (bugun > kayit.sonGun) throw new Error('gecikmis odunc yenilenemez');
  return {
    ...kayit,
    sonGun: bugun + KURALLAR[kayit.uyeTuru].oduncGun,
    yenilemeSayisi: kayit.yenilemeSayisi + 1,
  };
}
```

```sh
node --test --test-reporter=tap ornek.test.mjs | grep -E '^ *(ok|not ok|# (tests|pass|fail))'
```

```
    ok 1 - uyeTuru=ogrenci bugun=1020 sonGun=1028 -> sonGun=1048
    ok 2 - uyeTuru=uye bugun=1020 sonGun=1024 -> sonGun=1034
ok 1 - Yenileme son tarihi bugunden itibaren uye turunun odunc suresi kadar ileri alir
    ok 1 - bugun=1020 sonGun=1028 rezerveEdildi=evet -> hata=rezerve edilmis
ok 2 - Rezerve edilmis kitap yenilenemez
    ok 1 - bugun=1020 sonGun=1028 yenilemeSayisi=1 -> yenilemeSayisi=2
    ok 2 - bugun=1020 sonGun=1028 yenilemeSayisi=2 -> hata=en cok 2 kez
ok 3 - Bir odunc en cok iki kez yenilenebilir
    ok 1 - bugun=1029 sonGun=1028 -> hata=gecikmis odunc
    ok 2 - bugun=1028 sonGun=1028 -> sonGun=1056
ok 4 - Gecikmis odunc yenilenemez, son gunde yapilan yenileme kabul edilir
    ok 1 - bugun=1020 sonGun=1028 rezerveEdildi=evet siradakiUye=U-17 -> sonGun=1048
ok 5 - Rezervasyon sirasindaki ilk uye oduncu elinde tutan uyeyse yenileme kabul edilir
# tests 8
# pass 8
# fail 0
```

Eski rezervasyon örneği hâlâ yeşil, çünkü sıradaki üye varsayılan olarak başkasıdır. Yeni
kural eskisini geçersiz kılmadı, daralttı — ve bunu doğrulayan şey, tabloda ikisinin de
durmasıdır.

## Örneklerin Sınırı

Örnek tablosunun iki kazancı vardır ve ikisi de sınırlıdır.

Birinci kazanç ortak dildir: kural, kodu okumayan bir kişinin doğrulayabileceği biçimde
yazılıdır. Sınırı şudur ki tablo ancak konuşulan bir dille yazıldığı sürece bu işe yarar.
Alan sözcüğü yerine sınıf adı, kural cümlesi yerine yöntem imzası geçtiğinde tablo yalnız
daha zahmetli bir test dosyasına dönüşür.

İkinci kazanç, aynı kural için birden çok örneğin ucuzlamasıdır. Yeni bir sınır durumu bir
satırdır. Sınırı şudur ki her davranış tabloya sığmaz: koşum sırasına, zamana ya da çok
adımlı bir senaryoya bağlı davranışlar için tablo biçimi yetersiz kalır ve elle yazılmış
test daha açık olur. İki biçim birbirinin yerine değil, yan yana kullanılır.

Üçüncü bir uyarı çözümleyicinin kendisiyle ilgilidir. Tablodan test üreten kod, testlerin
tamamının doğruluğunun bağlı olduğu tek noktadır. Sessizce satır atlayan ya da beklenen
sonucu yanlış çözen bir çözümleyici, ikinci dersteki `assert.ok` kadar zararlıdır: her şey
yeşil görünür. Bu yüzden çözümleyici tanımadığı satırda hata fırlatır ve kendisi de sınanır.

## Özet

- Davranış odaklı geliştirme aynı döngüyü kullanır, ama konuşmanın birimi alan diliyle
  yazılmış bir örnektir: verilen durum, yapılan işlem, beklenen sonuç.
- Örnek biçimi bir standarda bağlı değildir; taşıması gereken tek şey hem insanın okuyabilmesi
  hem de programın ayrıştırabilmesidir.
- Veri güdümlü testte test gövdesi tektir ve girdi kümesi veriden gelir; geçen testlerin
  listesi doğrudan bir kural belgesi verir.
- Yeni bir kuralın kırmızı adımı tabloya eklenen iki satırdır; test dosyasına dokunulmaz.
- Tablo biçimi ortak dil ve ucuz sınır durumu sağlar, ama sıraya ya da zamana bağlı çok
  adımlı davranışlar için elle yazılmış test daha açıktır.

## Sonraki Adım

Bu derste örnekler tek bir işlevin sözleşmesini anlattı: yenileme kuralları. Bir kullanıcı
isteği ise bundan geniştir — "üye kitabının süresini uzatabilsin" cümlesi, bir işlevi değil
uçtan uca bir akışı tarif eder ve kabul edildiğini söyleyen ölçütler taşır. Sonraki ders o
ölçütleri otomatik bir denetime çevirir ve dış halkası kabul ölçütünde, iç halkası birim
testinde dönen iki katmanlı bir döngü kurar.
