---
title: 'Uyumluluk Testi'
source: 'https://academia.sh/tr/kurslar/islevsel-olmayan-test/uyumluluk-testi'
course: 'İşlevsel Olmayan Test'
language: tr
updated: '2026-08-17T18:10:52+00:00'
license: 'CC BY-SA 4.0'
---

# Uyumluluk Testi

Oluşturma motoru, platform ve ekran eksenlerinin çarpımıyla büyüyen matrisin ölçülmesi: özellik destek profillerinin ayrık sınıflara indirgenmesi, paya göre ve profile göre seçimlerin yakaladığı kusur farkı ve seçim ölçütünün eşikten daha belirleyici olması.

Önceki denetim tek bir belge modeli üzerinde koştu ve tek bir sonuç verdi. Oysa aynı ödünç
ekranı her okuyucuda aynı ağacı üretmez: farklı oluşturma motorları aynı bildirimi farklı
destekler, farklı ekran genişlikleri farklı düzen kurar. Buraya kadarki bütün ölçümler tek
bir ortamda yapıldı ve o ortamın temsil ettiği kullanıcı payı hiç sorulmadı.

**Uyumluluk testi** bu eksenlerin çarpımını bir matrise açar ve tek bir soruyu sorar: bu
matrisin hangi alt kümesi koşulacak? Tümleşim, Sözleşme ve Uçtan Uca Test kursundaki
aygıt–sürüm matrisi aynı aritmetiği aygıt ve işletim sürümü üzerinden kurmuştu; buradaki
matrisin ekseni aygıt değil **özellik destek profilidir** ve seçim ölçütü kullanıcı payından
değil profillerin ayrıklığından türer.

## Matris ve Destek Profilleri

Üç oluşturma motoru, iki platform ve iki ekran sınıfı on iki ortam veriyor. Altı özelliğin
her ortamdaki desteği bir vektördür; aynı vektörü taşıyan ortamlar özellik açısından
**ayırt edilemez**.

**IO14 (varsayım):** ortam payları ölçülmüştür ve matris eksiksizdir. Listede olmayan bir
ortam yoktur sayılır; bütün kapsama oranları bu on iki satıra görelidir.

```js
// matris.mjs — uyumluluk matrisi, ozellik destek profilleri ve bilinen kusurlar
export const OZELLIK = ["kalici depo", "gecis animasyonu", "izgara duzeni",
  "tarih bicimleyici", "gozlemci", "girdi onerisi"];

const MOTOR = { a: [1, 1, 1, 1, 1, 1], b: [1, 0, 0, 1, 1, 0], c: [1, 1, 1, 1, 0, 1] };

// Mobil platformda tarih bicimleyici (3. ozellik) hicbir motorda yok.
export const profil = (o) =>
  MOTOR[o.motor].map((v, i) => (i === 3 && o.platform === "mobil" ? 0 : v)).join("");

// Kullanici payi olculmus on iki ortam.
export const ORTAM = [
  { motor: "a", platform: "masaustu", ekran: "genis", pay: 42 },
  { motor: "a", platform: "mobil", ekran: "dar", pay: 26 },
  { motor: "b", platform: "masaustu", ekran: "genis", pay: 14 },
  { motor: "c", platform: "mobil", ekran: "dar", pay: 9 },
  { motor: "b", platform: "mobil", ekran: "dar", pay: 3 },
  { motor: "c", platform: "masaustu", ekran: "genis", pay: 2 },
  { motor: "a", platform: "masaustu", ekran: "dar", pay: 1.5 },
  { motor: "a", platform: "mobil", ekran: "genis", pay: 1 },
  { motor: "b", platform: "masaustu", ekran: "dar", pay: 0.7 },
  { motor: "c", platform: "masaustu", ekran: "dar", pay: 0.4 },
  { motor: "b", platform: "mobil", ekran: "genis", pay: 0.3 },
  { motor: "c", platform: "mobil", ekran: "genis", pay: 0.1 },
].map((o) => ({ ...o, ad: `${o.motor}-${o.platform}-${o.ekran}` }));

// Elle dogrulanmis kusurlar ve gorunduklari ortam kosulu.
export const KUSUR = [
  ["K1 izgara duzeni cizilmiyor", (o) => o.motor === "b"],
  ["K2 tarih bicimi bos donuyor", (o) => o.platform === "mobil"],
  ["K3 gozlemci olmadan liste yenilenmiyor", (o) => o.motor === "c"],
  ["K4 masaustu duzeni dar ekranda tasiyor", (o) => o.platform === "masaustu" && o.ekran === "dar"],
  ["K5 kuyruk istemcisi mobilde baglanti kuramiyor", (o) => o.motor === "b" && o.platform === "mobil"],
  ["K6 mobil duzen genis ekranda dagiliyor", (o) => o.platform === "mobil" && o.ekran === "genis"],
];

// Saglam davranislar; kati dogrulama bunlari da kirmiziya cevirir.
export const SAGLAM = [
  ["Y1 gecis animasyonu atlaniyor", (o) => o.motor === "b"],
  ["Y2 menu dar ekranda katlaniyor", (o) => o.ekran === "dar"],
];

export const bulunan = (secim, liste) => liste.filter(([, k]) => secim.some(k)).length;
export const kirmizi = (secim, liste) => secim.filter((o) => liste.some(([, k]) => k(o))).length;
```

## Üç Seçim Ölçütü

```js
// secim.mjs — matrisin buyuklugu, ayirt edici profiller ve uc secim olcutu
import { ORTAM, OZELLIK, KUSUR, SAGLAM, profil, bulunan, kirmizi } from "./matris.mjs";

const profiller = [...new Set(ORTAM.map(profil))];
console.log(`${ORTAM.length} ortam, ${OZELLIK.length} ozellik, ${profiller.length} ayirt edici destek profili`);
for (const p of profiller) {
  const uyan = ORTAM.filter((o) => profil(o) === p);
  console.log(`  ${p}  ${String(uyan.reduce((t, o) => t + o.pay, 0).toFixed(1)).padStart(5)}%  ${uyan.map((o) => o.ad).join(", ")}`);
}

// (a) Paya gore: paydan buyukten kucuge, birikimli pay esige ulasana kadar.
const payaGore = (esik) => {
  const s = [];
  for (const o of ORTAM) { if (s.reduce((t, x) => t + x.pay, 0) >= esik) break; s.push(o); }
  return s;
};
// (b) Profile gore: her destek profilinden payi en buyuk ortam.
const profileGore = profiller.map((p) => ORTAM.filter((o) => profil(o) === p)[0]);
// (c) Profil ve duzen: (b) uzerine eksik kalan platform-ekran ciftleri eklenir.
const cift = (o) => `${o.platform}-${o.ekran}`;
const profilVeDuzen = [...profileGore];
for (const o of ORTAM) if (!profilVeDuzen.some((x) => cift(x) === cift(o))) profilVeDuzen.push(o);

console.log(`\n${"secim".padEnd(18)}${"kosum".padStart(6)}${"pay".padStart(7)}${"profil".padStart(8)}${"kusur".padStart(7)}${"kirmizi kosum".padStart(15)}`);
for (const [ad, s] of [["paya gore %90", payaGore(90)], ["profile gore", profileGore],
  ["profil ve duzen", profilVeDuzen], ["tam matris", ORTAM]]) {
  console.log(`${ad.padEnd(18)}${String(s.length).padStart(6)}${`${s.reduce((t, o) => t + o.pay, 0).toFixed(1)}%`.padStart(7)}` +
    `${`${new Set(s.map(profil)).size}/${profiller.length}`.padStart(8)}${`${bulunan(s, KUSUR)}/${KUSUR.length}`.padStart(7)}` +
    `${String(kirmizi(s, SAGLAM)).padStart(15)}`);
}

const kacan = KUSUR.filter(([, k]) => !payaGore(90).some(k));
console.log(`\npaya gore secimin kacirdiklari:`);
for (const [ad] of kacan) console.log(`  ${ad}`);
```

```
12 ortam, 6 ozellik, 6 ayirt edici destek profili
  111111   43.5%  a-masaustu-genis, a-masaustu-dar
  111011   27.0%  a-mobil-dar, a-mobil-genis
  100110   14.7%  b-masaustu-genis, b-masaustu-dar
  111001    9.1%  c-mobil-dar, c-mobil-genis
  100010    3.3%  b-mobil-dar, b-mobil-genis
  111101    2.4%  c-masaustu-genis, c-masaustu-dar

secim              kosum    pay  profil  kusur  kirmizi kosum
paya gore %90          4  91.0%     4/6    3/6              3
profile gore           6  96.0%     6/6    4/6              4
profil ve duzen        8  98.5%     6/6    6/6              5
tam matris            12 100.0%     6/6    6/6              8

paya gore secimin kacirdiklari:
  K4 masaustu duzeni dar ekranda tasiyor
  K5 kuyruk istemcisi mobilde baglanti kuramiyor
  K6 mobil duzen genis ekranda dagiliyor
```

On iki ortam altı profile iniyor: özellik desteği açısından matris yarı yarıya küçük.
Paya göre seçim dört koşumla kullanıcıların %91'ini kapsıyor ama altı profilin dördünü
görüyor ve altı kusurun üçünü kaçırıyor. Kaçırdıklarının ortak özelliği ise ilginçtir:
üçü de **eksenlerin birleşiminden** doğuyor. Masaüstü düzeninin dar ekranda taşması hiçbir
motorun desteğiyle ilgili değil; iki eksenin birlikte aldığı bir değerle ilgili.

Profile göre seçim bu yüzden yeterli değil: altı koşumla bütün destek profillerini kapsıyor
ama düzen kusurlarını hâlâ göremiyor, çünkü destek vektörü ekran sınıfını hiç taşımıyor.
Sekiz koşumluk üçüncü seçim, eksik kalan platform–ekran çiftlerini ekleyerek altı kusurun
altısını da buluyor — tam matrisin üçte ikisi kadar koşumla.

## Eşik Taraması

Yaygın kural "kullanıcıların şu kadarını kapsa" biçiminde yazılır. Bu eşiğin ne
kazandırdığı taranabilir.

```js
// esik.mjs — kapsanan pay esigi taranir; yanlis gecme ve yanlis kalma sayilir
import { ORTAM, KUSUR, SAGLAM, profil, bulunan, kirmizi } from "./matris.mjs";

const payaGore = (esik) => {
  const s = [];
  for (const o of ORTAM) { if (s.reduce((t, x) => t + x.pay, 0) >= esik) break; s.push(o); }
  return s;
};
const profiller = new Set(ORTAM.map(profil)).size;

console.log(`${"pay esigi".padEnd(10)}${"kosum".padStart(6)}${"kapsanan".padStart(10)}${"profil".padStart(8)}` +
  `${"yanlis gecme".padStart(14)}${"yanlis kalma".padStart(14)}${"maliyet w=5".padStart(12)}`);
for (const e of [80, 90, 95, 99, 100]) {
  const s = payaGore(e);
  const gecme = KUSUR.length - bulunan(s, KUSUR), kalma = kirmizi(s, SAGLAM);
  console.log(`%${String(e).padEnd(9)}${String(s.length).padStart(6)}${`${s.reduce((t, o) => t + o.pay, 0).toFixed(1)}%`.padStart(10)}` +
    `${`${new Set(s.map(profil)).size}/${profiller}`.padStart(8)}${String(gecme).padStart(14)}${String(kalma).padStart(14)}` +
    `${String(kalma + 5 * gecme).padStart(12)}`);
}

// Profil ve duzen olcutuyle secilen kume ayni tabloya konur.
const cift = (o) => `${o.platform}-${o.ekran}`;
const s = [...new Set(ORTAM.map(profil))].map((p) => ORTAM.filter((o) => profil(o) === p)[0]);
for (const o of ORTAM) if (!s.some((x) => cift(x) === cift(o))) s.push(o);
const gecme = KUSUR.length - bulunan(s, KUSUR), kalma = kirmizi(s, SAGLAM);
console.log(`\nprofil ve duzen olcutu: ${s.length} kosum, yanlis gecme ${gecme}, yanlis kalma ${kalma},` +
  ` maliyet ${kalma + 5 * gecme}`);
console.log(`ayni maliyeti paya gore yakalamak icin gereken kosum: ${payaGore(99).length}`);
```

```
pay esigi  kosum  kapsanan  profil  yanlis gecme  yanlis kalma maliyet w=5
%80            3     82.0%     3/6             4             2          22
%90            4     91.0%     4/6             3             3          18
%95            6     96.0%     6/6             2             4          14
%99            9     99.2%     6/6             0             6           6
%100          12    100.0%     6/6             0             8           8

profil ve duzen olcutu: 8 kosum, yanlis gecme 0, yanlis kalma 5, maliyet 5
ayni maliyeti paya gore yakalamak icin gereken kosum: 9
```

**Yanlış geçme**, seçimin dışında kalan ortamda duran gerçek kusurdur; **yanlış kalma**,
sağlam ama farklı davranan bir ortamda katı doğrulamanın kırmızıya dönmesidir. İkisi ters
yönde hareket ediyor: ortam ekledikçe kaçan kusur azalıyor, boşa kırmızı dönen koşum
artıyor. Tam matris bile en iyi seçenek değil — sekiz kırmızı koşumun ikisi zaten
kaçınılmaz gürültü.

Asıl sonuç son iki satırdadır. Paya göre seçim bütün kusurları ancak dokuz koşumla
bulabiliyor; profil ve düzen ölçütü aynı sonucu sekiz koşumla veriyor ve maliyeti daha
düşük. **Eşiğin kaynağı** burada bir ölçüm değil bir yanılgıdır: kapsanan kullanıcı payı
sezgisel bir sayıdır ama kusurların dağılımıyla ilgisi yoktur. Kusur, kullanıcı payına göre
değil **ortam sınıfına göre** dağılır ve seçim ölçütü eşikten daha belirleyicidir.

**Kararın sahibi:** matris dışında kalan her ortam bilinen bir boşluktur. Yayım kararı
"tüm koşumlar yeşil" cümlesine değil, "şu kadar profil ve şu kadar düzen çifti koşuldu"
cümlesine bağlanır; koşulmayan sınıflar kayda geçer.

## Testin Bedeli

Koşumdan bağımsız bedel üç sayıdadır. Birincisi koşum sayısı: sekiz ortam, her biri kendi
kurulumunu, kendi verisini ve kendi zamanını ister; bu sayı eksen eklendikçe çarpımsal
büyür — bir eksene bir değer eklemek matrisi bir katına değil, bir çarpanına taşır.

İkincisi matrisin bakımı: destek vektörleri elle yazılmıştır ve bir motor bir özelliği
desteklemeye başladığında profil sayısı değişir. Güncellenmeyen bir destek tablosu, ayırt
edici saydığı iki ortamı boşuna koşturur ya da ayrı saymadığı iki ortamdan birini hiç
koşturmaz.

Üçüncüsü kırmızı koşumların elenmesi: sekiz koşumun beşi kırmızı döndü ve bunların ikisi
gerçek kusur değildi. Uyumluluk testinin kalıcı yükü budur — her ortam farkı kusur değildir
ve farkı kusurdan ayıran şey kural değil karardır.

## Özet

- Uyumluluk matrisi eksenlerin çarpımıdır; on iki ortam altı özellik üzerinden altı ayırt
  edici destek profiline indi ve matris özellik açısından yarıya küçüldü.
- Paya göre seçim dört koşumla kullanıcıların %91'ini kapsadı ama altı kusurun üçünü
  kaçırdı; kaçanların üçü de tek bir eksenden değil eksenlerin birleşiminden doğuyordu.
- Destek profili ekran sınıfını taşımadığı için profile göre seçim de yetmedi; profil ve
  düzen ölçütü sekiz koşumla altı kusurun altısını buldu — tam matrisin üçte ikisi kadar.
- Eşik taraması iki sütunu ters yönde hareket ettirdi: ortam eklendikçe yanlış geçme
  azaldı, yanlış kalma arttı. Tam matris bile en düşük maliyetli seçenek değildi.
- Kusurlar kullanıcı payına göre değil ortam sınıfına göre dağılır; seçim ölçütü kapsanan
  pay eşiğinden daha belirleyicidir.
- Bedel çarpımsaldır: her yeni eksen değeri matrisi bir çarpanla büyütür, destek tablosu
  elle bakım ister ve kırmızı koşumların bir bölümü her koşumda yeniden elenir.

## Sonraki Adım

Bu konunun altı dersi aynı sistemi altı ayrı yöntemle sınadı ve altısı da ortak bir
varsayımı paylaştı: sistemin parçaları çalışıyor. Statik tarama kodun metnine baktı, dinamik
test koşan servise istek gönderdi, bağımlılık taraması kurulu sürümleri kayıtlarla
eşleştirdi, sızma testi kuralların birleşimini sorguladı, erişilebilirlik denetimi çizilen
ağacı okudu, uyumluluk testi aynı ekranı farklı ortamlarda koşturdu. Yük de saldırı da
**dışarıdan** gelen bir baskıydı ve her ikisinde de sistemin kendisi ayaktaydı. Oysa ödünç
servisinin bağlı olduğu veritabanı yanıt vermeyi bıraktığında, kuyruk istemcisi mesajı
kaybettiğinde ya da katalog servisi yarım yanıt döndürdüğünde ne olacağı hiçbir derste
sınanmadı. Sonraki konu baskıyı dışarıdan içeriye taşır: arıza sistemin kendi parçalarından
birinde başlatılır ve sistemin bu arızayı nasıl karşıladığı ölçülür.
