---
title: 'Keşifsel Test'
source: 'https://academia.sh/tr/kurslar/test-sureci/kesifsel-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'
---

# Keşifsel Test

Betiği önceden yazılmamış sınamanın bir bütçe kalemine dönüştürülmesi: oturum kapsamının genişlik ile derinlik arasında bölünmesi, betikli kümenin göremediği kusur sınıfının yalnız derinlikle görünmesi, bulunan kusurun betiğe dönüşme oranı ve yirmi sürümlük ufukta kaçan hata ile net bedelin ölçülmesi.

Önceki dersin beş sırası da aynı on iki testin içinden seçim yaptı ve hiçbiri 93 puanlık
tabana dokunamadı. O tabanı üreten iki sınıftan biri `senaryo-disi`: yazılmış hiçbir
senaryonun geçmediği yollarda ortaya çıkan kusurlar. Bir sınıf, onu görecek bir test
yazılmadığı sürece sıralamayla bulunamaz.

**Keşifsel test** (exploratory testing) betiği önceden yazılmamış, yönü sınama sırasında
görülene göre belirlenen bir sınama biçimidir. Serbest olması yapılandırılmamış olduğu
anlamına gelmez: sınayan bir **oturum kapsamı** yazar — hangi bölgeye, ne kadar süreyle, ne
arayarak bakılacağı. Bu ders o kapsamı bir bütçe dağıtımı olarak kurar; dağıtılan kaynak
insan dikkatidir ve iki yöne birden harcanamaz.

## Genişlik ile Derinlik Aynı Bütçedendir

Sistemin sınanabilir yüzeyi iki boyutludur: kaç **yol** gezildiği (genişlik) ve her yolda ne
kadar ileri gidildiği (derinlik). Bir oturumun bedeli bu ikisinin çarpımıdır, dolayısıyla
sabit bütçede biri ötekinin karşılığıdır.

**TS11 (varsayım) — sürüm başına keşifsel oturum bütçesi 120 dakikadır**; bu, birinci dersin
otomatik test bütçesiyle (TS3) aynı büyüklüktür ve seçimi duyarlılık taramasıyla sınanır.
**TS12 (varsayım) — bir yolu bir derinlik seviyesi kadar sınamak 6 dakika sürer.** Bütçe
böylece 20 yol-derinlik birimidir.
**TS13 (varsayım) — her kusur bir yolda ve bir derinlikte durur; senaryo dışı kalan iki sınıf
tanımı gereği derindir (3–5), ötekiler 1–5 arasına dağılır.** Bu, sınıfın tanımından gelen bir
kısıttır: yazılı senaryoların geçtiği sığ yollarda duran bir kusur zaten betikli kümede
görünürdü.
**TS14 (varsayım) — bulunan bir sınıf bir sonraki sürümden başlayarak betikli kümeye
çevrilir**; testsiz bir sınıf için 45 dakika yazım artı sürüm başına 5 dakika koşum, envanterde
testi olan bir sınıf için yazım yoktur, bedel o testin sürüm başına dakikasıdır.

```js
// kutuphane/envanter.mjs — birinci dersin envanterinden bu derste gereken alanlar: her testin
// kusur sinifi ve bedel nicelikleri (surec, cagri, elle adim; M21/K03 ve K04 kapanis
// tablolarindan). Dakikaya cevrim birinci dersteki TS1 ve TS2 ile, aynen.
const HAM = [["T01", "kural-siniri", 0, 266, 0], ["T02", "sema-uyusmazligi", 1, 772, 0],
  ["T03", "goc-veri-kaybi", 1, 21, 0], ["T04", "sozlesme-alani", 2, 100, 0],
  ["T05", "arayuz-durumu", 2, 16477, 0], ["T06", "gorsel-sapma", 1, 784, 1],
  ["T07", "veri-buyumesi", 9, 55000, 0], ["T08", "sql-birlestirme", 0, 75, 7],
  ["T09", "bilinen-acik", 0, 10, 5], ["T10", "erisilebilirlik", 0, 14, 6],
  ["T11", "bozulmus-yanit", 1, 13, 5], ["T12", "kurtarma-eksigi", 2, 7, 10]];
export const TESTLER = HAM.map(([kod, sinif, surec, cagri, elle]) =>
  ({ kod, sinif, dk: 0.5 * surec + 0.0002 * cagri + 6 * elle }));
const AGIRLIK = [["kural-siniri", 9], ["sema-uyusmazligi", 6], ["goc-veri-kaybi", 4],
  ["sozlesme-alani", 5], ["arayuz-durumu", 8], ["gorsel-sapma", 3], ["veri-buyumesi", 4],
  ["sql-birlestirme", 3], ["bilinen-acik", 3], ["erisilebilirlik", 4], ["bozulmus-yanit", 3],
  ["kurtarma-eksigi", 2], ["senaryo-disi", 5], ["anlam-sapmasi", 4]];
export function kusurlar(tohum, n) {
  let x = tohum;
  const rast = () => { x = (1103515245 * x + 12345) % 2147483648; return x / 2147483648; };
  const toplam = AGIRLIK.reduce((a, [, w]) => a + w, 0);
  const liste = [];
  for (let i = 1; i <= n; i += 1) {
    let p = rast() * toplam, sinif = AGIRLIK[AGIRLIK.length - 1][0];
    for (const [s, w] of AGIRLIK) { p -= w; if (p < 0) { sinif = s; break; } }
    liste.push({ no: i, sinif, olasilik: 1 + Math.floor(rast() * 5),
      etki: 1 + Math.floor(rast() * 5), duzeltme: 15 + 15 * Math.floor(rast() * 8) });
  }
  return liste;
}
```

## Dört Kapsam, Yirmi Sürüm

Dört dağıtım aynı 120 dakikayı böler: yirmi yolu bir derinliğe kadar (E1), on yolu iki (E2),
beş yolu dört (E3), dört yolu beş (E4). Kapsamın hangi yolları kapsayacağı bir bilgi
sorunudur — plan kusurun nerede olduğunu bilmez, bu yüzden yol seçimi tohumlu ve rastgeledir
ve iki yüz çizimin ortalaması alınır. Ölçüm yirmi sürümlük ufuk boyunca yürür: her sürümde üç
kusur ortaya çıkar, bir oturum koşar, bulunan sınıf sonraki sürümden başlayarak betikli kümeye
girer.

```js
// kutuphane/kesif.mjs — kesifsel oturumu bir butce dagitimi olarak olcer.
// Girdi: kutuphane/envanter.mjs (birinci dersten devralinan test kumesi ve kusur kumesi).
import { TESTLER, kusurlar } from "./envanter.mjs";

const TOHUM = 20260731, N = 60, YOL = 20, BIRIM = 6, OTURUM = 120, CIZIM = 200;
const KAT = 6, ADAY = 20, PAY = N / ADAY;                        // TS5, TS6: surum basina 3 kusur
// Ikinci dersin yogunluk sirasinin butceye sigan dokuz kalemi; kalan siniflar betiksizdir.
const BETIKLI = new Set(["T01", "T02", "T03", "T04", "T05", "T06", "T07", "T08", "T09"]
  .map((k) => TESTLER.find((t) => t.kod === k).sinif));
// Betiksiz siniflar ikiye ayrilir: envanterde testi olan ama butceye girmeyenler (VARTEST)
// ve hicbir testin gormedigi ikisi (DERIN).
const VARTEST = new Map(TESTLER.filter((t) => BETIKLI.has(t.sinif) === false).map((t) => [t.sinif, t]));
const DERIN = new Set(["senaryo-disi", "anlam-sapmasi"]);
const v = (x, n = 1) => x.toFixed(n).replace(".", ",");
const g = (x, n) => String(x).padStart(n);
const uret = (t) => { let x = t;
  return () => { x = (1103515245 * x + 12345) % 2147483648; return x / 2147483648; }; };

// TS13: her kusur bir yolda ve bir derinlikte durur. Senaryo disi kalan iki sinif taniminca
// derindir (3-5); otekiler 1-5. Yol ve derinlik tohum 31417'den gelir.
const r0 = uret(31417);
const KUSUR = kusurlar(TOHUM, N).map((k) => ({ ...k, yol: 1 + Math.floor(r0() * YOL),
  derinlik: DERIN.has(k.sinif) ? 3 + Math.floor(r0() * 3) : 1 + Math.floor(r0() * 5) }));
const BETIKSIZ = KUSUR.filter((k) => BETIKLI.has(k.sinif) === false);

// Bir oturum p yolu d derinligine kadar gezer; bedeli p*d*BIRIM dakikadir. Kusur, yolu
// gezildiyse ve derinligi d'yi asmiyorsa bulunur; bulma ani o yolun sirasindan gelir.
const gez = (r, p) => { const y = Array.from({ length: YOL }, (_, j) => j + 1);
  for (let j = YOL - 1; j > 0; j -= 1) { const q = Math.floor(r() * (j + 1));
    [y[j], y[q]] = [y[q], y[j]]; }
  return y.slice(0, p); };

// Ufuk: ADAY surum, surum basina PAY kusur ve bir oturum. Bulunan sinif bir sonraki surumden
// baslayarak betige cevrilir (TS14) ve o siniftan sonra kusur kacmaz.
function ufuk(p, d, tohum, butce = OTURUM) {
  const r = uret(tohum), yolSayisi = Math.min(p, Math.floor(butce / (BIRIM * d))), o = [];
  for (let c = 0; c < CIZIM; c += 1) {
    const cevrik = new Map(); let bulunan = 0, an = 0, kacan = [];
    for (let s = 1; s <= ADAY; s += 1) {
      const yer = new Map(gez(r, yolSayisi).map((y, i) => [y, (i + 1) * d * BIRIM]));
      const yeni = [];
      for (const k of KUSUR.slice((s - 1) * PAY, s * PAY)) {
        if (BETIKLI.has(k.sinif) || cevrik.has(k.sinif)) continue;
        if (yer.has(k.yol) && k.derinlik <= d) { bulunan += 1; an += yer.get(k.yol); yeni.push(k.sinif); }
        else kacan.push(k);
      }
      for (const x of yeni) if (cevrik.has(x) === false) cevrik.set(x, s);
    }
    const bedel = [...cevrik].reduce((a, [x, s]) => a + (ADAY - s) *
      (VARTEST.has(x) ? VARTEST.get(x).dk : 5) + (VARTEST.has(x) ? 0 : 45), 0);
    o.push({ bulunan, an: an / (bulunan || 1), cevrik, bedel,
      testsiz: [...cevrik.keys()].filter((x) => DERIN.has(x)).length,
      disi: [...cevrik.keys()].filter((x) => VARTEST.has(x)).length,
      kacan: kacan.length, risk: kacan.reduce((a, k) => a + k.olasilik * k.etki, 0),
      duz: kacan.reduce((a, k) => a + k.duzeltme, 0) });
  }
  const ort = (f) => o.reduce((a, x) => a + f(x), 0) / CIZIM;
  return { p: yolSayisi, d, butce, bulunan: ort((x) => x.bulunan), an: ort((x) => x.an),
    testsiz: ort((x) => x.testsiz), disi: ort((x) => x.disi), kacan: ort((x) => x.kacan),
    risk: ort((x) => x.risk), bedel: ort((x) => x.bedel), duz: ort((x) => x.duz) };
}
const TABANDUZ = BETIKSIZ.reduce((a, k) => a + k.duzeltme, 0);
const net = (o) => KAT * (TABANDUZ - o.duz) - ADAY * o.butce - o.bedel;

console.log(`kusur kumesi tohum ${TOHUM}, ${N} kusur; yol ve derinlik tohum 31417, ${YOL} yol`);
console.log(`betikli kume ikinci dersin dokuz kalemi -> ${BETIKLI.size} sinif kapali; ` +
  `ufukta ${BETIKSIZ.length} betiksiz kusur, ${BETIKSIZ.filter((k) => DERIN.has(k.sinif)).length}'i testsiz iki sinifta`);
console.log("derinlik dagilimi (kusur sayisi): " + [1, 2, 3, 4, 5]
  .map((d) => d + ":" + KUSUR.filter((k) => k.derinlik === d).length).join("  "));

console.log(`\noturum butcesi TS11 = ${OTURUM} dk = ${OTURUM / BIRIM} yol-derinlik birimi; ` +
  `${ADAY} surum, ${CIZIM} cizim ortalamasi`);
console.log("kapsam                  yol  derinlik   bulunan   butce disi   testsiz   donusum   bulma ani");
const D = [[20, 1], [10, 2], [5, 4], [4, 5]].map(([p, d], i) => ufuk(p, d, 5501 + i));
D.forEach((o, i) => console.log(`E${i + 1} ${o.p} yol x derinlik ${o.d}`.padEnd(24) +
  g(o.p, 3) + g(o.d, 10) + g(v(o.bulunan, 2), 10) + g(v(o.disi, 2), 13) + g(v(o.testsiz, 2), 10) +
  g(v((o.disi + o.testsiz) / o.bulunan, 2), 10) + g(v(o.an), 12)));

console.log("\nufkun sonu — ikinci dersin yogunluk sirasi tek basina 18 kusur kaciriyordu");
console.log("kapsam   kacan hata   kacan risk   oturum dk   donusum dk   kacan hatadan kazanc   net dk");
D.forEach((o, i) => console.log(`E${i + 1}`.padEnd(9) + g(v(o.kacan, 2), 10) + g(v(o.risk), 13) +
  g(ADAY * o.butce, 12) + g(v(o.bedel, 0), 13) + g(v(KAT * (TABANDUZ - o.duz), 0), 23) + g(v(net(o), 0), 9)));
console.log(`oturumsuz taban: 18 kacan, 155 risk, duzeltme ${TABANDUZ} dk (TS5 ile ${KAT * TABANDUZ} dk)`);

console.log("\nTS11'in duyarliligi — E4'un derinligi (5) uc butcede; 120 dk satiri E4'un ta kendisi");
console.log("butce dk   gezilen yol   bulunan   testsiz   kacan hata   net dk");
for (const b of [60, 120, 240]) { const o = ufuk(YOL, 5, 5504, b);
  console.log(g(b, 8) + g(o.p, 14) + g(v(o.bulunan, 2), 10) + g(v(o.testsiz, 2), 10) +
    g(v(o.kacan, 2), 13) + g(v(net(o), 0), 9)); }
```

```
kusur kumesi tohum 20260731, 60 kusur; yol ve derinlik tohum 31417, 20 yol
betikli kume ikinci dersin dokuz kalemi -> 9 sinif kapali; ufukta 18 betiksiz kusur, 10'i testsiz iki sinifta
derinlik dagilimi (kusur sayisi): 1:18  2:10  3:13  4:8  5:11

oturum butcesi TS11 = 120 dk = 20 yol-derinlik birimi; 20 surum, 200 cizim ortalamasi
kapsam                  yol  derinlik   bulunan   butce disi   testsiz   donusum   bulma ani
E1 20 yol x derinlik 1   20         1      3,00         3,00      0,00      1,00        64,4
E2 10 yol x derinlik 2   10         2      2,04         2,04      0,00      1,00        63,0
E3 5 yol x derinlik 4     5         4      2,53         1,35      1,12      0,98        73,3
E4 4 yol x derinlik 5     4         5      2,75         1,29      1,42      0,98        74,8

ufkun sonu — ikinci dersin yogunluk sirasi tek basina 18 kusur kaciriyordu
kapsam   kacan hata   kacan risk   oturum dk   donusum dk   kacan hatadan kazanc   net dk
E1            12,00        114,0        2400         1281                   2610    -1071
E2            13,85        126,5        2400          867                   1881    -1386
E3            11,32        104,1        2400          729                   2831     -298
E4            10,39         95,2        2400          735                   3280      145
oturumsuz taban: 18 kacan, 155 risk, duzeltme 1260 dk (TS5 ile 7560 dk)

TS11'in duyarliligi — E4'un derinligi (5) uc butcede; 120 dk satiri E4'un ta kendisi
butce dk   gezilen yol   bulunan   testsiz   kacan hata   net dk
      60             2      1,57      0,90        13,81      202
     120             4      2,75      1,42        10,39      145
     240             8      4,09      1,79         6,27     -923
```

## Genişliğin Göremediği Sınıf

E1 yirmi yolun hepsini gezer ve bulabileceği her şeyi bulur: derinlik 1'de duran üç betiksiz
kusur. Bu üçü tam sayıdır, çizimden çizime değişmez — tam genişlikte rastlantı kalmaz. Buna
karşılık E1'in `testsiz` sütunu **0,00**'dır ve ne kadar çizim yapılırsa yapılsın 0,00 kalır.
Nedeni bir olasılık değil bir kısıttır: senaryo dışı kalan iki sınıfın kusurları 3'ten sığ bir
derinlikte durmaz, çünkü sığ olsalardı yazılı senaryolar zaten oradan geçerdi.

E4 aynı bütçeyle yalnız dört yola bakar ve daha az kusur bulur (2,75'e karşı 3,00) — ama
bulduklarının 1,42'si testsiz sınıftandır. **Genişlik daha çok kusur bulur, derinlik başka
türden kusur bulur.** İki dağıtım arasındaki fark bir verimlilik farkı değil, bir erişim
farkıdır; E1'in eksiği daha az çalışması değil, bakmadığı bir yerin olmasıdır.

Bulma anı bu erişimin bedelini gösterir: 63,0 ile 74,8 dakika arasında. Önceki dersin yoğunluk
sırası kusuru ortalama 18,2 dakikada haber veriyordu; keşifsel oturum dört katına yakın bir
gecikmeyle haber verir ve gecikme derinlikle birlikte artar, çünkü derin bir yolun sonuna
varmak zaman alır.

## Dönüşüm Oranı ve İki Tür Bulgu

Bulunan kusurun betikli kümeye dönüşme oranı dört dağıtımda da 0,98 ile 1,00 arasındadır:
oturumun bulduğu hemen her kusur yeni bir betikli teste yol açar. Bu, göründüğü kadar iyi bir
haber değildir, çünkü dönüşenler iki türdür.

**Bütçe dışı sınıf**, envanterde testi olan ama 120 dakikaya sığmadığı için plandan düşmüş
sınıftır — E1'in bulduğu üç sınıfın üçü de budur. Böyle bir bulgu yeni bilgi getirmez; birinci
dersin bütçe kararını tekrar sorar ve dönüşümü de o kararın bedelini geri getirir: E1'in
dönüşüm bedeli 1.281 dakikadır, çünkü çevrilen testler kalan her sürümde koşar. **Testsiz
sınıf** ise envanterde karşılığı olmayan sınıftır; dönüşümü 45 dakika yazım artı sürüm başına
5 dakikadır ve E4'ün 735 dakikalık dönüşüm bedelinin küçük parçasıdır.

Ayrım kararı değiştirir. Bütçe dışı bir sınıfın bulunması, keşifsel oturumun değil planın
sonucudur ve cevabı bir oturum değil bir bütçe tartışmasıdır. Testsiz bir sınıfın bulunması
ise oturumun kendi ürünüdür ve karşılığında kalıcı bir test bırakır.

## Ufkun Sonundaki Sayı

Yirmi sürümün sonunda önceki dersin sırası tek başına 18 kusur kaçırıyordu, 155 risk puanıyla.
Keşifsel oturum bu sayıyı her dağıtımda düşürür: E2 13,85'e, E1 12,00'a, E3 11,32'ye, E4
10,39'a. Kaçan risk 155'ten 95,2'ye iner — yani oturum yalnız daha az kusur kaçırmakla kalmaz,
kaçırdıkları da daha hafiftir, çünkü testsiz iki sınıf kaçanların ağır ucundaydı.

Net sütunu bunu bir karara bağlar. Yirmi sürümlük oturum bedeli 2.400 dakikadır ve yalnız E4
artıya geçer: 145 dakika. E1 kaçan hatayı 12'ye indirir ama 1.071 dakika zarar eder, çünkü
bulduğu her şey pahalı bir testin yeniden bütçeye alınmasını gerektirir. **Bir dağıtımın
kaçan hatayı azaltması onu haklı çıkarmaz; azalttığı kadarının bedeli de sayılır.**

TS11 taraması bunun sınırını verir. Bütçe 60 dakikaya indiğinde kaçan hata 13,81'e çıkar ama
net 202'ye yükselir; 240 dakikaya çıkarıldığında kaçan hata 6,27'ye iner ve net −923 olur.
Kaçan hata bütçeyle birlikte düşmeye devam eder, net etmez. Sıfır kaçan hata isteyen bir plan
bütçeyi tüketir; bu kursun her dersinde tekrarlanan takasın buradaki biçimi budur.

Kırmızı sonucun karşılığı da farklıdır. Bir keşifsel oturum yeşil ya da kırmızı vermez, bir
bulgu listesi verir; listedeki her satır ya bir kayıt açar ya bir test doğurur. Sürümü
durdurma yetkisi oturumda değildir — oturumun ürünü, sonraki sürümlerde sürümü durdurabilecek
bir betikli testtir.

## Özet

- Oturum kapsamı bir bütçedir: genişlik ile derinliğin çarpımı sabittir (TS11–TS12), biri
  ötekinin karşılığıdır.
- Tam genişlik (E1) derinlik 1'deki üç kusuru kesin bulur ama testsiz iki sınıfı hiç göremez;
  bu bir olasılık değil, sınıfın tanımından gelen bir kısıttır (TS13).
- Derin kapsam (E4) daha az kusur bulur (2,75'e karşı 3,00) ama bulduklarının 1,42'si testsiz
  sınıftandır; fark verimlilik değil erişim farkıdır.
- Dönüşüm oranı 0,98–1,00'dır, ama dönüşenlerin çoğu bütçe dışı sınıftır: yeni bilgi değil,
  bütçe kararının yeniden sorulmasıdır.
- Yirmi sürümde kaçan hata 18'den 10,39'a, kaçan risk 155'ten 95,2'ye iner; 2.400 dakikalık
  oturum bedeliyle yalnız derin kapsam artıya geçer (145 dakika).
- Bütçe 240 dakikaya çıkarıldığında kaçan hata 6,27'ye iner ve net −923 olur: kaçan hata
  bütçeyle düşmeye devam eder, net etmez.

## Sonraki Adım

Buraya kadar üç ders sınamanın kendisini dağıttı: hangi test, hangi sırayla, hangi kapsamda.
Üçünün de ortak bir sessiz varsayımı var — bir kusurun kusur olduğu, bir işin bittiğinin
belli olduğu. Oysa keşifsel oturumun `anlam-sapmasi` sınıfındaki bulguları tam bu noktada
tartışmaya açılır: sınayan bunu bir kusur sayar, geliştiren beklenen davranış sayar, ürün
tarafı ikisine de katılmaz. Kaçan hata sayısı bu durumda bir ölçüm değil bir anlaşmazlıktır.
Sonraki ders tamamlanma tanımını ve kabul ölçütünü ele alır: ölçütü kimin yazdığı, ne zaman
kapandığı ve belirsiz bırakılan bir ölçütün kaç birim yeniden açılan iş ürettiği.
