Ders 06 / 12
Test Seviyeleri
Birim, tümleşim, sistem ve kabul seviyelerinin kapsadıkları sınıra göre ayrılması, aynı kusurun üç seviyede yakalanması ve teşhis mesafesinin seviyeyle birlikte büyümesi.
İçindekiler
Önceki konu kalitenin ne olduğunu, hangi sorularla sınandığını ve sürecin bu sınamayı nasıl konumlandırdığını kurdu. Eksik olan, sınamanın kendi iç düzenidir. Aynı kusur, tek bir işlevi sınayan bir testle de bütün sistemi ayağa kaldıran bir testle de yakalanabilir; ikisinin maliyeti ve söylediği şey aynı değildir.
Bu ders testleri kapsadıkları sınıra göre ayırır. Sınıf adları — birim, tümleşim, sistem, kabul — bu tek ölçütün adlarıdır.
Seviyeyi Belirleyen Şey Kapsamdır
Birim testi (unit test) tek bir işlevi ya da modülü, başka hiçbir parçaya dokunmadan sınar. Girdisi doğrudan işlevin girdisidir, çıktısı doğrudan dönüş değeridir.
Tümleşim testi (integration test) iki ya da daha çok parçanın birlikte çalışmasını sınar. Kusur artık parçaların içinde değil, aralarındaki sözleşmede olabilir: yanlış sıralanan bağımsız değişken, uyuşmayan birim, beklenmedik boş değer.
Sistem testi (system test) bütün parçaları bir arada, gerçek giriş noktasından sınar. Sorusu, kullanıcının gördüğü sonucun doğru olup olmadığıdır.
Kabul testi (acceptance test) kapsam olarak sistem testiyle örtüşür; ayrıldığı yer ölçütün kaynağıdır. Kabul testinin beklenen sonucu ürünü kullanacak tarafın diliyle yazılır ve teslimin koşulunu oluşturur. İkinci derste ayrılan geçerleme sorusu bu seviyede sorulur.
Frontend Kalitesi kursundaki Test ve İzleme konusu aynı ayrımı tarayıcı bağlamında kurmuştu; burada seviyeler alandan bağımsız olarak ele alınır.
Aynı Kusur Üç Seviyede
Kitaplık üç dosyaya ayrılır. Kural katmanı tek bir gecikmenin ücretini hesaplar, toplama katmanı bir üyenin borcunu çıkarır, işlem katmanı iade fişini üretir.
// ucret.mjs — kural katmani: tek bir gecikmenin ucreti export const UCRETSIZ_GUN = 3; export const GUNLUK_UCRET = 2; export const UST_SINIR = 20; export function gecikmeUcreti(gecikmeGun) { return Math.max(gecikmeGun - UCRETSIZ_GUN, 0) * GUNLUK_UCRET; }
// borc.mjs — toplama katmani: bir uyenin butun gecikmelerinin toplami import { gecikmeUcreti } from './ucret.mjs'; export function uyeBorcu(oduncler) { return oduncler.reduce((toplam, o) => toplam + gecikmeUcreti(o.gecikmeGun), 0); }
// iade.mjs — islem katmani: iade fisinin uretilmesi import { gecikmeUcreti } from './ucret.mjs'; import { uyeBorcu } from './borc.mjs'; export function iadeFisi(uye, oduncler) { return { uyeNo: uye.no, kalemler: oduncler.map((o) => ({ kitap: o.kitap, ucret: gecikmeUcreti(o.gecikmeGun) })), toplam: uyeBorcu(oduncler), }; }
Kural katmanında bir kusur vardır: UST_SINIR tanımlı olduğu hâlde hesapta kullanılmaz.
Üç seviyede de aynı kusur aranır. Aşağıdaki blok üç test dosyasını üretir ve her birini
Node’un yerleşik test koşucusuyla ayrı ayrı çalıştırır. Çıktıdaki süre alanları ortama
bağlı olduğu için yalnız sonuç sayısı ve iddia iletisi süzülür.
cat > birim.test.mjs <<'EOF' import test from 'node:test'; import assert from 'node:assert/strict'; import { gecikmeUcreti } from './ucret.mjs'; test('tek gecikmenin ucreti ust siniri asmaz', () => { const ucret = gecikmeUcreti(100); assert.ok(ucret <= 20, `ucret ${ucret} birim`); }); EOF cat > tumlesim.test.mjs <<'EOF' import test from 'node:test'; import assert from 'node:assert/strict'; import { uyeBorcu } from './borc.mjs'; test('uyenin toplam borcu ust siniri asmaz', () => { const borc = uyeBorcu([{ gecikmeGun: 100 }, { gecikmeGun: 30 }]); assert.ok(borc <= 20, `borc ${borc} birim`); }); EOF cat > sistem.test.mjs <<'EOF' import test from 'node:test'; import assert from 'node:assert/strict'; import { iadeFisi } from './iade.mjs'; test('iade fisinin toplami ust siniri asmaz', () => { const fis = iadeFisi({ no: 7 }, [{ kitap: 'K-1', gecikmeGun: 100 }]); assert.ok(fis.toplam <= 20, `fis toplami ${fis.toplam} birim`); }); EOF for kume in birim tumlesim sistem; do node --test "$kume.test.mjs" > "$kume.log" 2>&1 printf '%-9s %s | %s\n' "$kume" "$(grep -E '^ℹ fail ' "$kume.log")" \ "$(grep -m1 AssertionError "$kume.log" | sed 's/.*: //')" done
birim ℹ fail 1 | ucret 194 birim tumlesim ℹ fail 1 | borc 248 birim sistem ℹ fail 1 | fis toplami 194 birim
Üç seviye de kusuru yakaladı. Bu, seviyelerin gereksiz olduğu anlamına gelmez; yakalamanın maliyeti farklıdır.
Teşhis Mesafesi
Bir testin düşmesi, kusurun nerede olduğunu doğrudan söylemez; yalnız kapsamı içinde bir yerde olduğunu söyler. Kapsam ne kadar genişse, kusurun aranacağı alan o kadar büyüktür.
// seviyeler.mjs — ayni kusurun uc seviyede yakalanmasi ve kapsadigi dosya sayisi import assert from 'node:assert/strict'; import { gecikmeUcreti } from './ucret.mjs'; import { uyeBorcu } from './borc.mjs'; import { iadeFisi } from './iade.mjs'; const SEVIYELER = [ { ad: 'birim', dosya: ['ucret.mjs'], denetim: () => assert.equal(gecikmeUcreti(100), 20), }, { ad: 'tumlesim', dosya: ['ucret.mjs', 'borc.mjs'], denetim: () => assert.equal(uyeBorcu([{ gecikmeGun: 100 }, { gecikmeGun: 2 }]), 20), }, { ad: 'sistem', dosya: ['ucret.mjs', 'borc.mjs', 'iade.mjs'], denetim: () => { const fis = iadeFisi({ no: 7 }, [{ kitap: 'K-1', gecikmeGun: 100 }]); assert.equal(fis.toplam, 20); }, }, ]; for (const s of SEVIYELER) { let sonuc = 'gecti'; try { s.denetim(); } catch { sonuc = 'dustu'; } console.log(`${s.ad.padEnd(9)}: ${sonuc} — ${s.dosya.length} dosya kapsaminda`); }
birim : dustu — 1 dosya kapsaminda tumlesim : dustu — 2 dosya kapsaminda sistem : dustu — 3 dosya kapsaminda
Birim testi düştüğünde bakılacak tek bir dosya vardır. Sistem testi düştüğünde kusur üç dosyadan herhangi birinde olabilir ve hangisi olduğunu bulmak ayrı bir çalışmadır. Buna teşhis mesafesi denebilir: testin düşmesiyle kusurun bulunması arasındaki iş.
Kapsamla birlikte büyüyen üç maliyet daha vardır. Kurulum maliyeti: sistem testi veri, yapılandırma ve giriş noktası ister. Süre: kapsam genişledikçe koşu süresi artar ve önceki dersteki geri bildirim noktası geriye kayar. Kırılganlık: kapsam içindeki her parça testi düşürebilir, bu yüzden geniş kapsamlı testler ilgisiz nedenlerle daha sık düşer — dördüncü derste anılan yanlış alarmın başlıca kaynağı budur.
Buna karşılık dar kapsamın da bir bedeli vardır. Birim testi parçaların arasındaki kusuru göremez: her parça kendi başına doğru çalışıp bir araya geldiklerinde yanlış sonuç üretebilirler. Yukarıdaki kusur her seviyede görünürdü, çünkü tek bir katmandaydı; sözleşme uyuşmazlıkları böyle davranmaz.
Seviyelerin Dağılımı
Seviyelerin göreli sayısı bir tercihtir ve iki uçtan biriyle anılır. Test piramidinde (test pyramid) taban geniştir: çok sayıda hızlı birim testi, daha az tümleşim testi, en üstte az sayıda sistem testi. Gerekçesi maliyet dağılımıdır — kusurların çoğu ucuz seviyede yakalanır, pahalı seviye yalnız parçaların birleşimini sınar.
Ters dizilime dondurma külahı (ice-cream cone) denir: az sayıda birim testi, çok sayıda sistem testi ve tepede el testi. Bu dizilimde her geri bildirim yavaş ve her düşen test pahalıdır.
Piramit bir kural değil, bir maliyet gözlemidir. Alan değiştikçe oranlar değişir: kuralı ağır bir hesap katmanı tabanı büyütür, ince bir arayüz katmanı üst seviyeye ağırlık verir. Karar verilirken sorulacak soru sabittir — bu kusur, en ucuz hangi seviyede yakalanabilir?
Özet
- Test seviyeleri ne sınadıklarıyla değil, kapsadıkları sınırla ayrılır: birim tek parçayı, tümleşim parçaların birleşimini, sistem bütünü sınar.
- Kabul testi kapsam olarak sistem testiyle örtüşür; ölçütünün ürünü kullanacak tarafın dilinden gelmesiyle ayrılır.
- Örnekte tek bir katmandaki kusur üç seviyede de yakalandı; ayrım yakalamada değil, yakalamanın maliyetindeydi.
- Kapsam genişledikçe teşhis mesafesi, kurulum maliyeti, süre ve kırılganlık birlikte büyür; dar kapsam ise parçalar arasındaki kusuru göremez.
- Test piramidi bir kural değil maliyet gözlemidir; karar ölçütü, kusurun en ucuz hangi seviyede yakalanacağıdır.
Sonraki Adım
Seviye, testin nereye kadar uzandığını belirler. Bağımsız bir soru daha vardır: testi yazan kişi neye bakarak yazdı? Yukarıdaki üç test de belirtimden türetildi — üst sınır kuralını okuyup onu sordular. Kodun içine bakılarak yazılsalardı başka sorular çıkardı, çünkü kodda belirtimde hiç bulunmayan yollar olabilir. Sonraki ders bu bilgi düzeyi ayrımını ele alır ve iki yaklaşımın farklı kusur türleri bulduğunu gösterir.
İlerlemeni kaydetmek ve not almak için Giriş yap
Notlarım
Not almak için giriş yapmalısın.