İçeriğe geç
academia.sh

Ders 09 / 12

Test Tasarım Teknikleri

Sonsuz girdi uzayından sonlu denetim kümesi seçmenin sistemli yolları: denklik sınıfları, sınır değer analizi ve koşul birleşimlerini eksiksiz sayan karar tablosu.

İçindekiler

Buraya kadar denetimlerin girdileri örnek olarak seçildi: 3 gün, 4 gün, 100 gün. Seçimin gerekçesi sezgiydi ve sezgi tekrarlanabilir değildir — aynı işlevi iki kişi sınadığında iki farklı küme çıkar, ikisinin de neyi kapsadığı belirsiz kalır.

Bu ders girdi seçimini gerekçelendirilebilir bir işleme dönüştürür. Üç teknik ele alınır: aynı davranan girdileri sınıflara ayırmak, sınıfların kenarlarını yoklamak ve koşul birleşimlerini eksiksiz saymak.

Girdi Uzayı Sonsuz, Denetim Sayısı Sonlu

Birinci derste kurulan sınır burada işlerlik kazanır: test kusurun varlığını gösterebilir, yokluğunu gösteremez, çünkü sonlu sayıda girdiyle sonsuz girdi kümesi denenemez. O hâlde sorulacak soru “hepsi denendi mi” değil, “denenenler neyi temsil ediyor” olmalıdır.

Test tasarım teknikleri bu temsil ilişkisini kurar. Her teknik, girdi uzayını bir ölçüte göre böler ve bölümlerden seçim yapmayı gerekçelendirir. Ölçüt yazılı olduğu için hangi girdilerin neden seçildiği ve neyin dışarıda kaldığı da yazılı olur.

Örnek olarak ödünç verme kararı kullanılır. Karar üç kurala bağlıdır: kitap başkası adına rezerve edilmişse verilmez, üyenin borcu sınıra ulaşmışsa verilmez, üyenin aktif ödünç sayısı türünün sınırına ulaşmışsa verilmez.

// karar.mjs — odunc kararinin uc kuralli uygulamasi
export const ODUNC_SINIRI = { ogrenci: 10, uye: 5 };
export const BORC_SINIRI = 20;

export function oduncKarari({ uyeTuru, aktifOdunc, borc, baskasinaRezerve }) {
  if (!(uyeTuru in ODUNC_SINIRI)) throw new Error(`bilinmeyen uye turu: ${uyeTuru}`);
  if (!Number.isInteger(aktifOdunc) || aktifOdunc < 0) throw new Error('aktif odunc gecersiz');
  if (baskasinaRezerve) return 'rezerve';
  if (borc > BORC_SINIRI) return 'borc';
  if (aktifOdunc >= ODUNC_SINIRI[uyeTuru]) return 'sinir';
  return 'verildi';
}

Denklik Sınıfları

Denklik sınıfı (equivalence class), programın aynı biçimde işlediği girdilerden oluşan kümedir. Varsayım şudur: bir sınıfın bir üyesi kusuru ortaya çıkarıyorsa, aynı sınıfın diğer üyeleri de çıkarır. Bu varsayım doğruysa sınıf başına bir temsilci yeterlidir.

Borç değeri iki sınıfa ayrılır: sınırın altındakiler ve sınıra ulaşanlar. Aktif ödünç sayısı da aynı biçimde ikiye ayrılır. Rezerve durumu zaten iki değerlidir.

// siniflar.mjs — her denklik sinifindan bir temsilci
import { oduncKarari } from './karar.mjs';

const temel = { uyeTuru: 'uye', aktifOdunc: 2, borc: 8, baskasinaRezerve: false };
const TEMSILCILER = [
  ['borc sinifi: sinir alti', { borc: 8 }, 'verildi'],
  ['borc sinifi: sinir ustu', { borc: 35 }, 'borc'],
  ['odunc sinifi: sinir alti', { aktifOdunc: 2 }, 'verildi'],
  ['odunc sinifi: sinir ustu', { aktifOdunc: 7 }, 'sinir'],
  ['rezerve: yok', { baskasinaRezerve: false }, 'verildi'],
  ['rezerve: var', { baskasinaRezerve: true }, 'rezerve'],
];

let gecen = 0;
for (const [ad, degisiklik, beklenen] of TEMSILCILER) {
  const gozlenen = oduncKarari({ ...temel, ...degisiklik });
  if (gozlenen === beklenen) gecen += 1;
  else console.log(`  sapma: ${ad} — beklenen ${beklenen}, gozlenen ${gozlenen}`);
}
console.log(`denklik siniflari: ${gecen}/${TEMSILCILER.length} temsilci uyustu`);
denklik siniflari: 6/6 temsilci uyustu

Altı temsilcinin altısı da uyuştu. Tekniğin getirisi burada görülür: on binlerce olası borç değeri yerine iki değer denendi ve her sınıfın kapsandığı yazılı hâle geldi.

Sınıflar ayrılırken iki tür ayrım yapılır. Geçerli sınıf (valid partition) programın kabul etmesi gereken girdileri, geçersiz sınıf (invalid partition) reddetmesi gerekenleri toplar — negatif ödünç sayısı ve bilinmeyen üye türü geçersiz sınıflardır. Geçersiz sınıflar tek tek denenir; iki geçersiz değer aynı denetimde birleştirilirse ilk reddin ikincisini gölgelemesi ve kusurun görünmez kalması olağandır.

Sınır Değer Analizi

Denklik sınıfının varsayımı bir yerde zayıflar: sınıfların kenarında. Kusurların büyük bölümü karşılaştırma operatörlerinde toplanır ve bir operatör hatası yalnız kenarda görünür — sınıfın ortasından seçilen temsilci onu göremez.

Sınır değer analizi (boundary value analysis) her sınıf kenarı için üç değer üretir: eşiğin bir altı, eşiğin kendisi ve bir üstü. Değerler elle değil, bildirilen eşiklerden türetilir; eşik değiştiğinde denetimler de kendiliğinden değişir.

// sinir.mjs — siniflarin kenarlarindan turetilen degerler
import { oduncKarari, ODUNC_SINIRI, BORC_SINIRI } from './karar.mjs';

const komsular = (esik) => [esik - 1, esik, esik + 1];
const temel = { uyeTuru: 'uye', aktifOdunc: 2, borc: 8, baskasinaRezerve: false };

const DENETIMLER = [
  ...komsular(BORC_SINIRI).map((borc) => ({
    ad: `borc=${borc}`, girdi: { borc }, beklenen: borc >= BORC_SINIRI ? 'borc' : 'verildi',
  })),
  ...komsular(ODUNC_SINIRI.uye).map((aktifOdunc) => ({
    ad: `aktifOdunc=${aktifOdunc}`, girdi: { aktifOdunc },
    beklenen: aktifOdunc >= ODUNC_SINIRI.uye ? 'sinir' : 'verildi',
  })),
];

let sapma = 0;
for (const d of DENETIMLER) {
  const gozlenen = oduncKarari({ ...temel, ...d.girdi });
  if (gozlenen !== d.beklenen) {
    sapma += 1;
    console.log(`  sapma: ${d.ad} — beklenen ${d.beklenen}, gozlenen ${gozlenen}`);
  }
}
console.log(`sinir degerleri: ${DENETIMLER.length} denetim, ${sapma} sapma`);
  sapma: borc=20 — beklenen borc, gozlenen verildi
sinir degerleri: 6 denetim, 1 sapma

Altı denetim, tek sapma. Borcu tam 20 birim olan üyeye ödünç veriliyor; kural “sınıra ulaşan” derken uygulama “sınırı aşan” diyor. Bu kusur, sınıfların ortasından seçilen hiçbir temsilciyle görünmezdi ve bir önceki kümede gerçekten de görünmedi.

Kaç değer denenmelidir? Üç değerli sınır (bir altı, eşik, bir üstü) yukarıdaki gibi bütün operatör hatalarını yakalar. İki değerli sınır (eşik ve bir üstü) daha ucuzdur ve aynı kusurların çoğunu bulur. Seçim, eşiğin taşıdığı riske göre yapılır — para, yetki ve süre eşiklerinde üç değer tercih edilir.

Karar Tablosu

Denklik sınıfları ve sınır değerleri girdileri tek tek ele alır. Kurallar birbirini etkilediğinde bu yetmez: hangi koşul birleşimlerinin denendiği ve hangilerinin atlandığı görünmez kalır.

Karar tablosu (decision table) koşulları satırlara, birleşimleri sütunlara yazar ve her birleşimin hangi eylemi ürettiğini belirtir. Üç koşul sekiz birleşim demektir; sayım programla yapıldığında hiçbiri atlanmaz.

// karar-tablosu.mjs — uc kosulun butun birlesimlerinin sayilmasi ve kural birlestirme
const KOSULLAR = ['rezerve', 'borc', 'odunc'];

function eylem([rezerve, borc, sinir]) {
  if (rezerve) return 'rezerve';
  if (borc) return 'borc';
  if (sinir) return 'sinir';
  return 'verildi';
}

const birlesimler = [];
for (let i = 0; i < 2 ** KOSULLAR.length; i += 1) {
  const satir = KOSULLAR.map((_, j) => Boolean((i >> (KOSULLAR.length - 1 - j)) & 1));
  birlesimler.push({ satir, eylem: eylem(satir) });
}

console.log(`tam sayim: ${birlesimler.length} birlesim (${KOSULLAR.join(' / ')})`);
for (const b of birlesimler) {
  console.log(`  ${b.satir.map((v) => (v ? 'E' : 'H')).join(' ')} -> ${b.eylem}`);
}

const gruplar = new Map();
for (const b of birlesimler) {
  if (!gruplar.has(b.eylem)) gruplar.set(b.eylem, []);
  gruplar.get(b.eylem).push(b.satir);
}

console.log(`birlestirilmis kural sayisi: ${gruplar.size}`);
for (const [ey, satirlar] of gruplar) {
  const kural = KOSULLAR.map((_, j) => {
    const degerler = new Set(satirlar.map((s) => s[j]));
    return degerler.size === 1 ? ([...degerler][0] ? 'E' : 'H') : '-';
  });
  const kapsam = kural.reduce((n, k) => n * (k === '-' ? 2 : 1), 1);
  console.log(`  ${kural.join(' ')} -> ${ey.padEnd(7)} ${satirlar.length} birlesim, kural ${kapsam} birlesim kapsiyor`);
}
tam sayim: 8 birlesim (rezerve / borc / odunc)
  H H H -> verildi
  H H E -> sinir
  H E H -> borc
  H E E -> borc
  E H H -> rezerve
  E H E -> rezerve
  E E H -> rezerve
  E E E -> rezerve
birlestirilmis kural sayisi: 4
  H H H -> verildi 1 birlesim, kural 1 birlesim kapsiyor
  H H E -> sinir   1 birlesim, kural 1 birlesim kapsiyor
  H E - -> borc    2 birlesim, kural 2 birlesim kapsiyor
  E - - -> rezerve 4 birlesim, kural 4 birlesim kapsiyor

Sekiz birleşim dört kurala indi. - işareti ilgisiz koşulu (don’t care) gösterir: kitap başkası adına rezerve edilmişse borç ve ödünç sayısı sonucu değiştirmez, çünkü rezerve denetimi diğerlerinden önce gelir. Birleştirmenin doğruluğu son sütunda sağlanır — kuralın kapsadığı birleşim sayısı, gruptaki birleşim sayısına eşit olmalıdır.

Karar tablosunun asıl getirisi, kuralların önceliğini görünür kılmasıdır. Borcu sınırda ve kitabı rezerve olan bir üyeye hangi yanıt verilecek? Tablo bu soruyu sormaya zorlar; belirtim bunu yazmamışsa eksiklik tablo çizilirken ortaya çıkar. Denetim sayısı da kararlı biçimde belirlenir: dört kural için dört denetim yeterlidir, sekiz denetim gereksizdir.

Koşul sayısı arttıkça birleşim sayısı iki katına çıkar; on koşul bin yirmi dört birleşim demektir. Bu noktada tam sayım bırakılır ve her koşulun sonucu tek başına belirlediği birleşimler seçilir. Seçim ölçütü değişir, tablonun kendisi değişmez.

Tekniklerin İş Bölümü

Üç teknik aynı soruyu farklı yerlerden yanıtlar ve birbirinin yerine geçmez.

Denklik sınıfları girdi uzayını küçültür ve neyin temsil edildiğini yazılı kılar. Sınır değerleri sınıfların kenarındaki kusurları yakalar — örnekte tek kusuru yalnız bu teknik buldu. Karar tablosu koşul birleşimlerinin eksiksiz sayılmasını sağlar ve belirtimdeki öncelik boşluklarını görünür yapar.

Sıralı davranışların kendi tekniği vardır: bir kaydın durumdan duruma geçişi söz konusuysa denenmesi gereken şey değerler değil geçişlerdir. Bu teknik son derste ele alınır.

Özet

  • Test tasarım teknikleri girdi seçimini sezgiden çıkarıp gerekçelendirilebilir bir işleme çevirir; ölçüt yazılı olduğu için neyin dışarıda kaldığı da yazılı olur.
  • Denklik sınıfı, programın aynı biçimde işlediği girdilerin kümesidir; sınıf başına bir temsilci varsayımı sınıfın ortasında geçerli, kenarında zayıftır.
  • Geçersiz sınıflar tek tek denenir; birleştirildiklerinde ilk ret ikincisini gölgeler.
  • Sınır değer analizi eşiğin bir altını, eşiği ve bir üstünü dener; örnekte borcu tam sınırda olan üyeye ödünç verildiği kusuru yalnız bu teknik buldu.
  • Karar tablosu koşul birleşimlerini eksiksiz sayar, ilgisiz koşulları birleştirerek denetim sayısını düşürür ve belirtimdeki öncelik boşluklarını görünür kılar.

Sonraki Adım

Teknikler hangi girdilerin deneneceğini belirledi. Denenen şeyin bir başkasına anlatılabilmesi ayrı bir iştir: hangi durumda başlanacak, hangi adımlar izlenecek, ne gözlenecek? Otomatik denetim bu bilgiyi kodun içinde taşır ve yalnız kodu okuyan kişiye anlatır. Sonraki ders bu bilgiyi yazılı bir biçime kavuşturur ve o biçimden çalıştırılabilir teste geçişi gösterir.

İlerlemeni kaydetmek ve not almak için Giriş yap

Notlarım

Not almak için giriş yapmalısın.

Aramak için yazmaya başlayın.

↑↓ Esc gezin · aç · kapat