İçeriğe geç
academia.sh

Ders 08 / 12

İşlevsel Test Türleri

Duman, sağlık, gerileme, yeniden test ve kabul testinin amaçlarına göre ayrılması, aynı sürümde farklı kusurları yakalamaları ve gerileme kümesinin bakım maliyeti.

İçindekiler

Seviye ve bilgi düzeyi bir testin yerini belirler, amacını belirlemez. Aynı kara kutu birim testi, sürümün ayakta olup olmadığını anlamak için de koşturulabilir, giderilmiş bir kusurun geri gelip gelmediğini denetlemek için de. İkisinde de test aynıdır; değişen şey neden koşturulduğu ve sonucundan ne yapılacağıdır.

Bu ders testleri amaçlarına göre adlandırır. Adların işlevi, bir kümenin ne zaman koşturulacağı ve düştüğünde ne yapılacağı konusunda ortak bir anlayış kurmaktır.

Amaç Testi Adlandırır

Duman testi (smoke test) geniş ve sığdır: her ana yolu bir kez dener, hiçbirini derinlemesine sınamaz. Sorusu tek cümledir — bu sürüm üzerinde çalışmaya değer mi? Düştüğünde verilecek karar da tektir: sürüm geri çevrilir, ayrıntılı sınamaya girilmez.

Sağlık testi (sanity test) dar ve derindir: belirli bir değişikliğin dokunduğu bölgeyi birkaç dakikada yoklar. Sorusu şudur — bu düzeltme makul görünüyor mu? Tam kümeyi koşturmadan önce yapılan bir ön elemedir.

Gerileme testi (regression test) daha önce çalışan bir davranışın bozulup bozulmadığını sınar. Kümesi zamanla birikir: her giderilen kusur, geri geldiğinde uyaracak bir nöbetçi bırakır.

Yeniden test (confirmation test) giderildiği bildirilen tek bir kusurun gerçekten giderildiğini sınar. Hata kaydındaki adımların birebir tekrarıdır ve kapsamı o kayıttan ibarettir.

Kabul testi teslimin koşuludur ve ölçütü ürünü kullanacak taraftan gelir; önceki iki derste tanımlanan yeri budur.

Duman ve Gerileme Aynı Sürümde

Kitaplığın üç sürümü kurulur: sağlam sürüm, çekirdek bir işlemi bozulmuş sürüm ve daha önce giderilmiş bir kusuru geri gelmiş sürüm.

// surum.mjs — kitapligin saglam surumu ve iki bozuk surumu
export function temelKitaplik() {
  return {
    uyeBul: (no) => (no >= 0 ? { no, tur: no % 3 === 0 ? 'ogrenci' : 'uye' } : null),
    gecikmeUcreti: (gun) => Math.min(Math.max(gun - 3, 0) * 2, 20),
    oduncVer: (uye, kitap) => ({ uyeNo: uye.no, kitap, durum: 'verildi' }),
  };
}

export const SURUMLER = {
  'S0 saglam': temelKitaplik(),
  'S1 cekirdek bozuk': { ...temelKitaplik(), oduncVer: () => { throw new Error('kayit acilamadi'); } },
  'S2 eski kusur geri geldi': { ...temelKitaplik(), gecikmeUcreti: (gun) => Math.max(gun - 3, 0) * 2 },
};

Duman kümesi üç ana yolu birer kez dener. Gerileme kümesi ise üç hata kaydının nöbetçisidir; her denetimin adı geldiği kaydın numarasını taşır.

// turler.mjs — duman ve gerileme kumelerinin uc surumde karsilastirilmasi
import assert from 'node:assert/strict';
import { SURUMLER } from './surum.mjs';

const DUMAN = {
  'uye kaydi acilir': (k) => assert.ok(k.uyeBul(41)),
  'odunc verilir': (k) => assert.equal(k.oduncVer(k.uyeBul(41), 'K-1').durum, 'verildi'),
  'ucret hesaplanir': (k) => assert.equal(typeof k.gecikmeUcreti(5), 'number'),
};

const GERILEME = {
  'H-14 ucret ust siniri asmaz': (k) => assert.equal(k.gecikmeUcreti(100), 20),
  'H-22 ucretsiz gun payi uc gundur': (k) => assert.equal(k.gecikmeUcreti(3), 0),
  'H-31 gecersiz uye numarasi bos doner': (k) => assert.equal(k.uyeBul(-1), null),
};

function kostur(kume, kitaplik) {
  const dusen = [];
  for (const [ad, denetim] of Object.entries(kume)) {
    try { denetim(kitaplik); } catch { dusen.push(ad); }
  }
  return dusen;
}

for (const [surumAdi, kitaplik] of Object.entries(SURUMLER)) {
  const satir = [];
  for (const [kumeAdi, kume] of [['duman', DUMAN], ['gerileme', GERILEME]]) {
    const dusen = kostur(kume, kitaplik);
    satir.push(`${kumeAdi} ${Object.keys(kume).length - dusen.length}/${Object.keys(kume).length}${dusen.length ? ` (${dusen[0]})` : ''}`);
  }
  console.log(`${surumAdi.padEnd(24)}: ${satir.join(' | ')}`);
}
S0 saglam               : duman 3/3 | gerileme 3/3
S1 cekirdek bozuk       : duman 2/3 (odunc verilir) | gerileme 3/3
S2 eski kusur geri geldi: duman 3/3 | gerileme 2/3 (H-14 ucret ust siniri asmaz)

İki kusur, iki ayrı küme tarafından yakalandı. Çekirdek işlem bozulduğunda gerileme kümesi susuyor, çünkü nöbetçileri geçmiş kusurların bölgesine yerleşmiştir; ödünç verme hiç kusur çıkarmadığı için orada nöbetçi yoktur. Eski kusur geri geldiğinde duman kümesi susuyor, çünkü ücret hesabına yalnız bir sayı dönüp dönmediğini soruyordu.

İki kümenin de amacı doğrudur ve ikisi de eksiktir. Bu eksiklik bir kusur değil, tanımın sonucudur: sığ küme derinliği, dar küme genişliği bilmez.

Yeniden Test Tek Başına Yetmez

Ücret kusuru için düzeltme yapılır. Düzeltmeyi yazan kişi üst sınırı geri koyar, ama ücretsiz gün payını düşürür.

// saglik.mjs — yeniden test, saglik testi ve gerileme kumesinin ayni duzeltmede verdigi sonuc
import assert from 'node:assert/strict';
import { temelKitaplik } from './surum.mjs';

const duzeltilmis = { ...temelKitaplik(), gecikmeUcreti: (gun) => Math.min(gun * 2, 20) };

const YENIDEN_TEST = {
  'H-14 kayittaki durum': () => assert.equal(duzeltilmis.gecikmeUcreti(100), 20),
};

const SAGLIK = {
  'ucret 0 gunde 0': () => assert.equal(duzeltilmis.gecikmeUcreti(0), 0),
  'ucret 3 gunde 0': () => assert.equal(duzeltilmis.gecikmeUcreti(3), 0),
  'ucret 4 gunde 2': () => assert.equal(duzeltilmis.gecikmeUcreti(4), 2),
  'ucret 13 gunde 20': () => assert.equal(duzeltilmis.gecikmeUcreti(13), 20),
  'ucret 14 gunde 20': () => assert.equal(duzeltilmis.gecikmeUcreti(14), 20),
};

const GERILEME = {
  'H-14 ucret ust siniri asmaz': () => assert.equal(duzeltilmis.gecikmeUcreti(100), 20),
  'H-22 ucretsiz gun payi uc gundur': () => assert.equal(duzeltilmis.gecikmeUcreti(3), 0),
  'H-31 gecersiz uye numarasi bos doner': () => assert.equal(duzeltilmis.uyeBul(-1), null),
};

for (const [ad, kume] of [['yeniden test', YENIDEN_TEST], ['saglik testi', SAGLIK], ['gerileme   ', GERILEME]]) {
  const dusen = Object.entries(kume).filter(([, d]) => { try { d(); return false; } catch { return true; } });
  console.log(`${ad}: ${Object.keys(kume).length - dusen.length}/${Object.keys(kume).length} gecti${dusen.length ? ` — ilk dusen: ${dusen[0][0]}` : ''}`);
}
yeniden test: 1/1 gecti
saglik testi: 3/5 gecti — ilk dusen: ucret 3 gunde 0
gerileme   : 2/3 gecti — ilk dusen: H-22 ucretsiz gun payi uc gundur

Yeniden test geçti: hata kaydındaki durum artık doğru sonucu veriyor. Kayıt kapatılabilirdi. Sağlık testi ise aynı bölgede birkaç saniye içinde ikinci bir bozulma gösterdi — düzeltme kendi çevresine zarar vermiş.

Buradan iki kural çıkar. Bir kusur giderildiğinde yalnız kayıttaki durum değil, o kuralın sınır değerleri de sınanır. Ve yeniden testin geçmesi kaydı kapatmaya yetmez; giderilen kusurun bölgesi ayrıca yoklanır.

Kümelerin Bakım Maliyeti

Gerileme kümesi tek yönlü büyür: her yeni kusur bir nöbetçi ekler, hiçbiri kendiliğinden çıkmaz. Zamanla küme, geri bildirim noktasını geriye itecek kadar yavaşlar.

Üç tutamak vardır. Seçmeli gerileme (regression test selection) yalnız değişen bölgeye dokunan denetimleri koşturur; tam küme daha geride bir noktaya bırakılır. Ayıklama, karşılığı kalmamış kuralın nöbetçisini kaldırır — kural yoksa nöbetçi de yoktur. Kırılgan testlerin ayıklanması ise güveni korur: ilgisiz nedenlerle düşen bir denetim, düştüğünde kimsenin bakmadığı bir gürültüye dönüşür ve kümenin tamamının değerini düşürür.

Duman kümesinin bakımı ters yöndedir: küçük kalmalıdır. Bir duman kümesi büyüdükçe kendi işini yapamaz hâle gelir, çünkü hızlı yanıt vermek onun tek işidir.

Özet

  • Test türleri amaçlarına göre ayrılır: duman geniş ve sığ, sağlık dar ve derin, gerileme geçmiş kusurların nöbetçisi, yeniden test tek bir kaydın tekrarıdır.
  • Örnekte çekirdek bozulmayı yalnız duman kümesi, geri gelen kusuru yalnız gerileme kümesi yakaladı; iki kümenin de eksikliği tanımlarının sonucudur.
  • Yeniden testin geçmesi kusurun giderildiğini gösterir, düzeltmenin çevresine zarar vermediğini göstermez; örnekte sağlık testi ikinci bozulmayı ortaya çıkardı.
  • Gerileme kümesi tek yönlü büyür; seçmeli koşturma, karşılığı kalmamış denetimlerin ayıklanması ve kırılgan testlerin giderilmesi bakımının parçalarıdır.
  • Duman kümesinin bakımı küçük kalmasıdır; büyüdüğünde hızlı yanıt verme işlevini yitirir.

Sonraki Adım

Buraya kadar denetimlerin girdileri örnek olarak seçildi: 3 gün, 4 gün, 100 gün. Seçimin gerekçesi sezgiydi. Sonsuz girdi kümesinden sonlu bir alt küme seçmenin sistemli yolları vardır ve bu yollar hangi girdilerin denendiğini gerekçelendirir. Sonraki ders bu teknikleri kurar: aynı davranan girdileri sınıflara ayırmak, sınıfların kenarlarını yoklamak ve koşul birleşimlerini eksiksiz saymak.

İ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