---
title: 'Sürekli Tümleştirmede Test'
source: 'https://academia.sh/tr/kurslar/test-sureci/surekli-tumlestirmede-test'
course: 'Test Süreci ve Otomasyon Altyapısı'
language: tr
updated: '2026-08-17T18:10:53+00:00'
license: 'CC BY-SA 4.0'
---

# Sürekli Tümleştirmede Test

Dört kursun bıraktığı sınamaların bir hatta yerleştirilmesi: aşama ve kapı düzeninin geri bildirim süresi ile kaçan hata arasında kurduğu takas, erken kesmenin koşum bütçesine etkisi, gecelik ve sürüm kapılarının bekleme bedeli ve karantinanın kapı kararına bağlanması.

Önceki konu bir dağıtım bıraktı: kapsam yazıldı, risk sırası kuruldu, keşifsel oturumun
kapsamı belirlendi, kabul ölçütü tamamlanma tanımına bağlandı. Hepsinin ortak yanı şudur —
bu dağıtım **kâğıt üzerindedir**. Bir plan, her değişiklikte kendiliğinden işleyen bir
düzeneğe bağlanmadığı sürece yalnızca bir niyettir; kimin ne zaman hangi testi koşacağı
insanın hatırlamasına kalır.

Bu ders o düzeneği kurar. Değişikliği alıp sırayla sınamalardan geçiren zincire **hat**
(pipeline) denir; hattın her parçası bir **aşama** (stage), aşamanın sonucunun bir kararı
zorladığı nokta ise bir **kapı**dır (gate). Kabuk Programlama kursundaki **boru hattı** bir
sürecin çıktısını diğerinin girdisine bağlar; buradaki hat ise bir değişikliğin geçmesi
gereken sıralı sınama kümesidir, veri değil karar taşır. Sorulan şey tek bir sayıyla
yazılabilir: hangi sınama hangi aşamada koşarsa geri bildirim süresi ile **kaçan hata**
(escaped defect, önceki kursların **kaçan gerçek hata** kavramıyla aynı şey) arasındaki takas
nereye düşer.

## Sınama Envanteri

Dört kurs otuz ders boyunca sınama yazdı ve her dersin kapanış tablosu o sınamanın
koşumdan bağımsız bedelini bıraktı. O sayılar burada dokuz **sınama takımı**na toplanır.
Süreç sayısı, ağ isteği, veri erişimi ve elle inceleme adımı doğrudan kapanış
tablolarından okunmuştur: tümleşim takımının 816 erişimi Tümleşim Testinin Kapsamı (4
sorgu), Test Ortamı Yönetimi (6 adım), Test Verisi Yönetimi (772 sorgu), Veritabanı
Testleri (21 sorgu, 13 göç adımı) ve Dış Servis Taklidi (0) satırlarının toplamıdır;
güvenlik takımının 20 elle adımı beş güvenlik dersinin elle inceleme sayılarının
toplamıdır.

**TS6 — koşum bedeli model dakikasıdır: bir süreç ayağa kaldırma 1 dakika, bin ağ isteği 1
dakika, bin veri erişimi 1 dakika, bir elle inceleme adımı 15 dakika; taban 1 dakika.** Elle
adımın ağırlığı diğerlerinin on beş katıdır, çünkü elle iş bir kapıya konulamaz — sırasını
bekler.

**TS7 — yüz değişiklikte kusur sınıfı başına ortaya çıkma sayısı.** Alt katmanların gördüğü
sınıflar daha sık yazılır, çünkü her değişiklik koda dokunur; kapasite ve kurtarma sınıfları
seyrektir. İki sınıfın **yakalayan** listesi boştur: bunlar kaynak derslerin "yakalamadığı"
sütunundan gelir ve hiçbir takımın göremediği kusurlardır.

```js
// envanter.mjs — dort kursta yazilan sinamalarin takim listesi, bedeli ve kusur kumesi
const yukari = (n) => Math.ceil(n / 1000);

// TS6: surec 1 dk, bin istek 1 dk, bin erisim 1 dk, elle adim 15 dk; taban 1 dk.
export const bedel = (t) => Math.max(1,
  t.surec + yukari(t.istek) + yukari(t.erisim) + t.elle * 15);

// surec / istek / erisim / elle sayilari M21/K03 ve K04 kapanis tablolarindan okundu.
export const takimlar = [
  { ad: 'birim', surec: 0, istek: 0, erisim: 9, elle: 0 },
  { ad: 'sozlesme', surec: 6, istek: 126, erisim: 0, elle: 0 },
  { ad: 'tumlesim', surec: 1, istek: 0, erisim: 816, elle: 0 },
  { ad: 'uctan-uca', surec: 12, istek: 24, erisim: 25511, elle: 0 },
  { ad: 'basarim-kosum', surec: 44, istek: 78939, erisim: 0, elle: 0 },
  { ad: 'basarim-ornekleme', surec: 0, istek: 0, erisim: 536000, elle: 0 },
  { ad: 'guvenlik-otomatik', surec: 9, istek: 8, erisim: 183, elle: 0 },
  { ad: 'guvenlik-elle', surec: 0, istek: 0, erisim: 0, elle: 20 },
  { ad: 'dayaniklilik', surec: 0, istek: 639, erisim: 20, elle: 0 },
];

// TS7: yuz degisiklikte kusur sinifi basina ortaya cikma sayisi.
export const kusurlar = [
  { sinif: 'sinir karsilastirmasi', yakalayan: ['birim'], sayi: 13 },
  { sinif: 'sema uyusmazligi', yakalayan: ['tumlesim'], sayi: 8 },
  { sinif: 'kart durumunun guncellenmemesi', yakalayan: ['uctan-uca'], sayi: 7 },
  { sinif: 'durum kodu eslemesi', yakalayan: ['uctan-uca'], sayi: 6 },
  { sinif: 'kirici degisiklik', yakalayan: ['birim', 'sozlesme'], sayi: 6 },
  { sinif: 'istek bicimi kaymasi', yakalayan: ['sozlesme'], sayi: 5 },
  { sinif: 'erisilebilirlik olcutu', yakalayan: ['guvenlik-elle'], sayi: 5 },
  { sinif: 'sozlesmedeki alanin kaybolmasi', yakalayan: ['sozlesme'], sayi: 4 },
  { sinif: 'reddedilen istekte uyari yoklugu', yakalayan: ['uctan-uca'], sayi: 4, karantina: true },
  { sinif: 'gecikme gerilemesi', yakalayan: ['basarim-kosum'], sayi: 4 },
  { sinif: 'gocte veri kaybi', yakalayan: ['tumlesim'], sayi: 3 },
  { sinif: 'birlestirilmis sorgu', yakalayan: ['guvenlik-otomatik'], sayi: 3 },
  { sinif: 'anlamsal uyusmazlik', yakalayan: [], sayi: 3 },
  { sinif: 'kontrol-sonra-yaz yarisi', yakalayan: ['uctan-uca'], sayi: 2 },
  { sinif: 'dagilima bagli rapor kusuru', yakalayan: ['tumlesim'], sayi: 2 },
  { sinif: 'surec omrune bagli durum', yakalayan: [], sayi: 2 },
  { sinif: 'az ornekle okunan yuzdelik', yakalayan: ['basarim-ornekleme'], sayi: 1 },
  { sinif: 'kurtarma eksigi', yakalayan: ['dayaniklilik'], sayi: 1 },
  { sinif: 'kapasite siniri', yakalayan: ['dayaniklilik'], sayi: 1 },
];
```

```js
// bedel.mjs — takim basina kosum bedeli ve kusur kumesinin toplami
import { takimlar, kusurlar, bedel } from './envanter.mjs';

const s = (x, n) => String(x).padStart(n);
console.log(`${'takim'.padEnd(20)}${s('surec', 6)}${s('istek', 8)}${s('erisim', 8)}${s('elle', 6)}${s('dakika', 8)}`);
for (const t of takimlar) {
  console.log(`${t.ad.padEnd(20)}${s(t.surec, 6)}${s(t.istek, 8)}${s(t.erisim, 8)}${s(t.elle, 6)}${s(bedel(t), 8)}`);
}
const toplam = takimlar.reduce((a, t) => a + bedel(t), 0);
const kusurToplam = kusurlar.reduce((a, k) => a + k.sayi, 0);
const gorulmeyen = kusurlar.filter((k) => k.yakalayan.length === 0);
console.log(`\ntakim ${takimlar.length}, tam takim ${toplam} dakika`);
console.log(`kusur sinifi ${kusurlar.length}, yuz degisiklikte ${kusurToplam} kusur, `
  + `${100 - kusurToplam} temiz degisiklik`);
console.log(`hicbir takimin gormedigi sinif ${gorulmeyen.length}, `
  + `${gorulmeyen.reduce((a, k) => a + k.sayi, 0)} kusur`);
```

```
takim                surec   istek  erisim  elle  dakika
birim                    0       0       9     0       1
sozlesme                 6     126       0     0       7
tumlesim                 1       0     816     0       2
uctan-uca               12      24   25511     0      39
basarim-kosum           44   78939       0     0     123
basarim-ornekleme        0       0  536000     0     536
guvenlik-otomatik        9       8     183     0      11
guvenlik-elle            0       0       0    20     300
dayaniklilik             0     639      20     0       2

takim 9, tam takim 1021 dakika
kusur sinifi 19, yuz degisiklikte 80 kusur, 20 temiz degisiklik
hicbir takimin gormedigi sinif 2, 5 kusur
```

Tam takım 1021 dakikadır, yani on yedi saat. Bu sayı kararı zaten vermiştir: her
değişiklikte tam takımı koşturmak bir seçenek değildir. Piramidin aritmetiği Test Piramidi
dersinde yapıldı; burada piramit **zamana** çevrilir — birim takımı 1 dakika, uçtan uca
takımı 39, başarım takımının örnekleme çalışması tek başına 536 dakikadır.

## Kapı Düzenleri

Bir düzen, aşamaların sırasını ve her aşamanın **sıklığını** belirler: her değişiklikte,
gecelik ya da sürüm başına. Sıklık bir bekleme üretir.

**TS8 — bekleme süreleri: gecelik kapı için 240 dakika, sürüm kapısı için 1200 dakika.**
Değişiklikler iş gününe düzgün yayılır; gecelik koşum gün sonunda bir kez çalışır, yani
ortalama bekleme yarım iş günüdür. Sürüm haftada birdir, ortalama bekleme iki buçuk iş
günüdür.

**TS9 — yüz değişiklik yirmi iş gününe yayılır: günde beş değişiklik, dört sürüm.** Bu
varsayım koşum sayısını belirler ve makine bedelini doğrudan etkiler.

**TS10 — bir koşucu günde 480 dakika iş yapar.** Gereken koşucu sayısı buradan çıkar ve
düzenin donanım bedelidir.

**Erken kesme** (fail fast), bir aşama kırmızıya döndüğünde sonraki aşamaların hiç
koşmamasıdır. Aşağıdaki ölçüm bunu bir seçenek olarak açıp kapatır.

```js
// kapi.mjs — ayni kusur kumesi uzerinde yedi kapi duzeninin karsilastirilmasi
import { takimlar, kusurlar, bedel } from './envanter.mjs';

const dk = Object.fromEntries(takimlar.map((t) => [t.ad, bedel(t)]));
const BEKLEME = { degisiklik: 0, gecelik: 240, surum: 1200 };   // TS8
const KOSUM = { degisiklik: 100, gecelik: 20, surum: 4 };       // TS9

const A = ['birim', 'sozlesme'];
const B = ['tumlesim', 'uctan-uca'];
const C = ['basarim-kosum', 'guvenlik-otomatik', 'dayaniklilik'];
const D = ['basarim-ornekleme', 'guvenlik-elle'];

const duzenler = [
  { ad: 'tek kapi', kes: true, asamalar: [['hepsi', 'degisiklik', [...A, ...B, ...C, ...D]]] },
  { ad: 'uc asama', kes: true, asamalar: [['hizli', 'degisiklik', A], ['orta', 'degisiklik', B], ['agir', 'degisiklik', [...C, ...D]]] },
  { ad: 'uc asama, kesmesiz', kes: false, asamalar: [['hizli', 'degisiklik', A], ['orta', 'degisiklik', B], ['agir', 'degisiklik', [...C, ...D]]] },
  { ad: 'agir asama gecelik', kes: true, asamalar: [['hizli', 'degisiklik', A], ['orta', 'degisiklik', B], ['agir', 'gecelik', [...C, ...D]]] },
  { ad: 'uc siklik', kes: true, asamalar: [['hizli', 'degisiklik', A], ['orta', 'degisiklik', B], ['agir', 'gecelik', C], ['surum', 'surum', D]] },
  { ad: 'elle is hat disi', kes: true, asamalar: [['hizli', 'degisiklik', A], ['orta', 'degisiklik', B], ['agir', 'gecelik', C], ['surum', 'surum', ['basarim-ornekleme']]] },
  { ad: 'uc siklik, karantina', kes: true, karantina: true, asamalar: [['hizli', 'degisiklik', A], ['orta', 'degisiklik', B], ['agir', 'gecelik', C], ['surum', 'surum', D]] },
];

const olc = (d) => {
  const asama = d.asamalar.map(([ad, siklik, tk]) => ({ ad, siklik, tk, sure: tk.reduce((a, x) => a + dk[x], 0) }));
  const oncekiSure = (i) => {
    const s = asama[i].siklik;
    const dahaSik = asama.filter((x) => KOSUM[x.siklik] > KOSUM[s]).reduce((a, x) => a + x.sure, 0);
    const ayni = asama.slice(0, i + 1).filter((x) => x.siklik === s).reduce((a, x) => a + x.sure, 0);
    return dahaSik + BEKLEME[s] + ayni;
  };
  let kacan = 0, agirlik = 0, toplamGeri = 0, enKotu = 0, kesilen = 0;
  for (const k of kusurlar) {
    const gorur = (t) => k.yakalayan.includes(t) && (d.karantina !== true || k.karantina !== true);
    const i = asama.findIndex((x) => x.tk.some(gorur));
    if (i === -1) { kacan += k.sayi; continue; }
    const geri = oncekiSure(i);
    agirlik += k.sayi;
    toplamGeri += geri * k.sayi;
    enKotu = Math.max(enKotu, geri);
    // erken kesme: kirmizi asamadan sonraki degisiklik asamalari kosmaz
    if (d.kes && asama[i].siklik === 'degisiklik') {
      kesilen += k.sayi * asama.slice(i + 1).filter((x) => x.siklik === 'degisiklik').reduce((a, x) => a + x.sure, 0);
    }
  }
  const makine = (asama.reduce((a, x) => a + x.sure * KOSUM[x.siklik], 0) - kesilen) / 100;
  return { makine, kosucu: Math.ceil((makine * 5) / 480), geri: toplamGeri / agirlik, enKotu, kacan };
};

const s = (x, n) => String(x).padStart(n);
console.log(`${'duzen'.padEnd(22)}${s('dk/degisiklik', 14)}${s('kosucu', 8)}${s('ort geri', 10)}${s('en kotu', 9)}${s('kacan/100', 11)}`);
for (const d of duzenler) {
  const r = olc(d);
  console.log(`${d.ad.padEnd(22)}${s(r.makine.toFixed(1), 14)}${s(r.kosucu, 8)}`
    + `${s(r.geri.toFixed(1), 10)}${s(r.enKotu, 9)}${s(r.kacan, 11)}`);
}
const sure = (g) => g.reduce((a, x) => a + dk[x], 0);
console.log(`\nasama sureleri: hizli ${sure(A)}, orta ${sure(B)}, gecelik ${sure(C)}, surum ${sure(D)} dakika`);
console.log(`gece penceresi 480 dakika; agir asamanin tamami ${sure([...C, ...D])} dakika, `
  + `${sure([...C, ...D]) <= 480 ? 'sigar' : 'sigmaz'}`);
```

```
duzen                  dk/degisiklik  kosucu  ort geri  en kotu  kacan/100
tek kapi                      1021.0      11    1021.0     1021          5
uc asama                       426.3       5     228.1     1021          5
uc asama, kesmesiz            1021.0      11     228.1     1021          5
agir asama gecelik             231.9       3     276.1     1261          5
uc siklik                       98.2       2     252.6     2221          5
elle is hat disi                86.2       1     107.7     1921         10
uc siklik, karantina            98.2       2     264.0     2221          9

asama sureleri: hizli 8, orta 41, gecelik 136, surum 836 dakika
gece penceresi 480 dakika; agir asamanin tamami 972 dakika, sigmaz
```

## Tablonun Okunması

İlk iki satır aşamalara bölmenin ne kazandırdığını verir. Tek kapı düzeninde her kusur
1021 dakika sonra görünür, çünkü sonuç ancak takımın tamamı bitince çıkar. Aynı takım üç
aşamaya bölündüğünde ortalama geri bildirim 228,1 dakikaya iner — kaçan hata değişmez,
kaçırılan kusur kümesi aynıdır. Bölme tek başına bedava bir kazançtır ve kaybı yoktur.

Üçüncü satır **erken kesmenin** payını ayırır. Aynı düzen, kesme kapalıyken değişiklik
başına 1021 dakika ve on bir koşucu ister; kesme açıkken 426,3 dakika ve beş koşucu. Geri
bildirim süresi iki satırda aynıdır: erken kesme kimseye daha erken haber vermez, yalnız
kırmızı bir değişikliğin ardından koşacak 1013 dakikalık işi iptal eder. Kazanç yüzde
elli sekizdir ve doğrudan kusur sıklığından gelir — kusursuz bir depoda erken kesme hiçbir
şey kazandırmaz.

Dördüncü ve beşinci satırlar sıklığın bedelini gösterir. Ağır aşama gecelik kapıya
taşındığında değişiklik başına 231,9 dakika kalır, ama son satır bir sorun bildiriyor:
ağır aşamanın tamamı 972 dakikadır ve 480 dakikalık gece penceresine sığmaz. Gecelik bir
kapı, gece bitmeden bitmek zorundadır. Bu yüzden ağır aşama ikiye ayrılır — başarım koşumu,
otomatik güvenlik taraması ve dayanıklılık testleri gecelik (136 dakika, pencereye sığar),
başarım örneklemesi ve elle güvenlik incelemesi sürüm kapısına. Üç sıklık düzeni değişiklik
başına 98,2 dakikaya ve iki koşucuya iner; karşılığında en kötü geri bildirim 1021'den
2221 dakikaya çıkar.

Altıncı satır bu kursun kuralının en açık örneğidir. Elle güvenlik incelemesi hattan
tamamen çıkarıldığında değişiklik başına 86,2 dakika ve tek koşucu yeter, ortalama geri
bildirim 107,7 dakikaya düşer — **ve kaçan hata beşten ona çıkar.** Ortalamanın iyileşmesi
bir kazanç değil, bir ölçüm tuzağıdır: en geç yakalanan sınıf artık hiç yakalanmadığı için
ortalamanın paydasından da çıkmıştır. Geri bildirim süresi tek başına okunduğunda, testi
silmek her zaman iyi görünür.

Son satır karantinayı kapı kararına bağlar. Kırılganlık Yönetimi dersinde karantinaya
alınan uçtan uca test hattan çıkarıldığında koşum bedeli değişmez (98,2 dakika aynıdır,
çünkü takımın süresi başka testlerce belirlenir) ama koruduğu kusur sınıfı kaçar: beşten
dokuza. Karantina bir bakım kararı gibi görünür; tabloda bir kapı kararıdır.

İlk beş satırda kaçan hata beşte sabit kalıyor. Bu beş kusur iki sınıftandır ve hiçbir
düzen onları yakalamaz — anlamsal uyuşmazlık ile süreç ömrüne bağlı durum, kaynak derslerin
"yakalamadığı" sütunundan gelir. **Sıfır kaçan hata isteyen bir düzen yoktur;** en pahalı
düzen bile beşini kaçırır, çünkü envanterde o sınıfı gören bir sınama yazılmamıştır.

## Kararın Geri Dönüşü

Bir kapının değeri, kırmızı sonucunun ne yaptığındadır. Hızlı ve orta aşamalar
**birleştirmeyi engeller**: sonuç kırmızıysa değişiklik ana dala girmez ve sahibi hâlâ o
işin başındadır. Gecelik kapı birleştirmeyi engelleyemez, çünkü değişiklik çoktan
girmiştir; kırmızı sonucu bir **kayıt açar** ve o kaydın sahibi gecelik koşuma giren
değişiklik kümesidir — kim olduğu tek tek belli değildir, bu da 240 dakikalık beklemenin
ikinci bedelidir. Sürüm kapısı **yayımı durdurur** ve kararın sahibi tek bir kişi değil,
sürümü onaylayan ekiptir.

Bu üç geri dönüş, aşama yerleşiminin asıl ölçütüdür: bir sınama, sonucunun karşılığı olan
kararın verilebildiği en erken aşamaya konur. Elle güvenlik incelemesinin sürüm kapısında
olması bir eksiklik değil, elle işin doğasıdır — sıra bekler ve otomatik bir kapıya konamaz.

## Özet

- Dört kursun otuz dersi dokuz sınama takımına toplandı; tam takım 1021 model dakikasıdır
  ve bedellerin tamamı kaynak derslerin kapanış tablolarından okundu.
- Takımı üç aşamaya bölmek ortalama geri bildirimi 1021'den 228,1 dakikaya indirdi ve
  kaçan hatayı değiştirmedi.
- Erken kesme geri bildirimi hiç değiştirmeden değişiklik başına makine bedelini 1021'den
  426,3 dakikaya, koşucu sayısını on birden beşe indirdi.
- Ağır aşamanın tamamı 972 dakikadır ve 480 dakikalık gece penceresine sığmaz; ikiye
  ayrıldığında değişiklik başına bedel 98,2 dakikaya iner, en kötü geri bildirim 2221'e çıkar.
- Elle incelemeyi hattan çıkarmak ortalama geri bildirimi 107,7 dakikaya düşürdü ve kaçan
  hatayı beşten ona çıkardı; karantinadaki testin çıkarılması kaçan hatayı dokuza taşıdı.
- Hiçbir düzen kaçan hatayı sıfırlamadı: iki kusur sınıfını envanterdeki hiçbir sınama
  görmüyor.

## Sonraki Adım

Bu tablonun her satırı bir varsayıma yaslanıyor: aşamanın süresi, sınamanın kendi koşum
bedelidir. Oysa hızlı aşama dışındaki her takım bir **test ortamı** ister — tümleşim takımı
bir bağımlı servis, uçtan uca takımı ayakta bir sistem, başarım takımı üretim benzeri bir
ortam. Bu ortamlar sonsuz değildir. İki değişiklik aynı anda geldiğinde biri bekler ve
beklediği süre aşamanın süresine eklenir; ortam çoğaltıldığında bekleme düşer ama maliyet
doğrusal büyür. Sonraki ders kaç ortamın hangi aşamada tutulacağını, paylaşılan ortamın
kuyruk süresini ve ayrı ortamın bedelini sayar.
